150 lines
3.6 KiB
TypeScript
150 lines
3.6 KiB
TypeScript
// ── Date utilities ──
|
|
// Uses moment.js which is bundled with Obsidian.
|
|
// Period format helpers following O-vault conventions.
|
|
|
|
import { moment } from 'obsidian';
|
|
|
|
export interface PeriodInfo {
|
|
day: string; // yyyy-MM-dd
|
|
week: string; // GGGG-[W]WW
|
|
month: string; // yyyy-MM
|
|
quarter: string; // yyyy-[Q]Q
|
|
year: string; // yyyy
|
|
}
|
|
|
|
export interface CalendarDay {
|
|
date: moment.Moment;
|
|
dayOfMonth: number;
|
|
isToday: boolean;
|
|
isCurrentMonth: boolean;
|
|
isoWeekNumber: number;
|
|
}
|
|
|
|
export interface CalendarWeek {
|
|
weekNumber: number;
|
|
days: CalendarDay[];
|
|
}
|
|
|
|
/**
|
|
* Get period info for a given date.
|
|
*/
|
|
export function getPeriodInfo(date: moment.Moment): PeriodInfo {
|
|
return {
|
|
day: date.format('YYYY-MM-DD'),
|
|
week: date.format('GGGG-[W]WW'),
|
|
month: date.format('YYYY-MM'),
|
|
quarter: date.format('YYYY-[Q]Q'),
|
|
year: date.format('YYYY'),
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Get quarter string from a moment date (e.g. "2026-Q3").
|
|
*/
|
|
export function getQuarterString(date: moment.Moment): string {
|
|
return date.format('YYYY-[Q]Q');
|
|
}
|
|
|
|
/**
|
|
* Get the current date's period info.
|
|
*/
|
|
export function getTodayPeriod(): PeriodInfo {
|
|
return getPeriodInfo(moment());
|
|
}
|
|
|
|
/**
|
|
* Build a month grid as an array of weeks.
|
|
* Each week has 7 days, starting on the configured first day of week.
|
|
* ISO week numbers are calculated from the Monday of that week row.
|
|
*/
|
|
export function getMonthGrid(
|
|
year: number,
|
|
month: number, // 0-indexed (0 = January)
|
|
firstDayOfWeek: number, // 0 = Sunday, 1 = Monday
|
|
): CalendarWeek[] {
|
|
const firstOfMonth = moment({ year, month, day: 1 });
|
|
const lastOfMonth = moment(firstOfMonth).endOf('month');
|
|
|
|
// Find the first day to display (may go back into previous month)
|
|
const startDate = moment(firstOfMonth)
|
|
.subtract((firstOfMonth.day() - firstDayOfWeek + 7) % 7, 'days');
|
|
|
|
const today = moment().startOf('day');
|
|
const weeks: CalendarWeek[] = [];
|
|
let currentDay = moment(startDate);
|
|
|
|
while (currentDay.isBefore(lastOfMonth) || currentDay.month() === month) {
|
|
const weekDays: CalendarDay[] = [];
|
|
|
|
for (let i = 0; i < 7; i++) {
|
|
weekDays.push({
|
|
date: moment(currentDay),
|
|
dayOfMonth: currentDay.date(),
|
|
isToday: currentDay.isSame(today, 'day'),
|
|
isCurrentMonth: currentDay.month() === month,
|
|
isoWeekNumber: currentDay.isoWeek(),
|
|
});
|
|
currentDay.add(1, 'day');
|
|
}
|
|
|
|
weeks.push({
|
|
weekNumber: weekDays[0].isoWeekNumber,
|
|
days: weekDays,
|
|
});
|
|
|
|
// Safety: break after 6 weeks
|
|
if (weeks.length >= 6) break;
|
|
}
|
|
|
|
return weeks;
|
|
}
|
|
|
|
/**
|
|
* Format a date label for the breadcrumb (e.g. "June 1st, 2026").
|
|
*/
|
|
export function formatDateLabel(date: moment.Moment): string {
|
|
return date.format('MMMM Do, YYYY');
|
|
}
|
|
|
|
/**
|
|
* Format a month label (e.g. "June 2026").
|
|
*/
|
|
export function formatMonthLabel(date: moment.Moment): string {
|
|
return date.format('MMMM YYYY');
|
|
}
|
|
|
|
/**
|
|
* Get readable quarter label (e.g. "Q3 2026").
|
|
*/
|
|
export function formatQuarterLabel(date: moment.Moment): string {
|
|
return date.format('[Q]Q YYYY');
|
|
}
|
|
|
|
/**
|
|
* Navigate a date by a given period and amount.
|
|
*/
|
|
export function navigateDate(
|
|
date: moment.Moment,
|
|
period: 'day' | 'week' | 'month' | 'quarter' | 'year',
|
|
delta: number,
|
|
): moment.Moment {
|
|
if (period === 'quarter') {
|
|
return moment(date).add(delta * 3, 'months');
|
|
}
|
|
return moment(date).add(delta, period);
|
|
}
|
|
|
|
/**
|
|
* Create a note filename from a date using the given format string.
|
|
*/
|
|
export function formatPeriodName(date: moment.Moment, format: string): string {
|
|
return date.format(format);
|
|
}
|
|
|
|
/**
|
|
* Get ISO week number for a given date.
|
|
*/
|
|
export function getISOWeek(date: moment.Moment): number {
|
|
return date.isoWeek();
|
|
}
|