Files

53 lines
1.9 KiB
TypeScript

/**
* Hitung Ayam 0-based day index for the Dashboard daily report.
* Day 0 = cycle start (DOC in). Feed/weight pages are 1-based and must be
* converted before joining. Local calendar dates only — never toISOString().
*/
export function parseLocalDateString(value: string): Date {
if (/^\d{4}-\d{2}-\d{2}$/.test(value)) {
const year = Number(value.slice(0, 4));
const month = Number(value.slice(5, 7));
const day = Number(value.slice(8, 10));
return new Date(year, month - 1, day);
}
const parsed = new Date(value);
parsed.setHours(0, 0, 0, 0);
return parsed;
}
const toLocalMidnight = (value: Date | string): Date => {
if (typeof value === 'string') return parseLocalDateString(value);
const date = new Date(value);
date.setHours(0, 0, 0, 0);
return date;
};
/** YYYY-MM-DD from local parts. Do not use toISOString() (WIB off-by-one). */
export function formatLocalDate(date: Date): string {
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
return `${year}-${month}-${day}`;
}
/** Calendar date of a Hitung Ayam day. Day 0 is the cycle start. */
export function reportDayToDate(cycleStart: Date | string, day: number): Date {
const start = toLocalMidnight(cycleStart);
start.setDate(start.getDate() + day);
return start;
}
/** Hitung Ayam day index for a calendar date. Cycle start → 0. */
export function dateToReportDay(cycleStart: Date | string, date: Date | string): number {
const start = toLocalMidnight(cycleStart);
const target = toLocalMidnight(date);
const diffMs = target.getTime() - start.getTime();
return Math.round(diffMs / (1000 * 60 * 60 * 24));
}
/** Feed/weight pages label cycle start as day 1; report labels it day 0. */
export function feedOrWeightDayToReportDay(oneBasedDay: number): number {
return oneBasedDay - 1;
}