refactor progress

This commit is contained in:
Hampus Kraft
2026-02-17 12:22:36 +00:00
parent cb31608523
commit d5abd1a7e4
8257 changed files with 1190207 additions and 761040 deletions

View File

@@ -0,0 +1,59 @@
/*
* Copyright (C) 2026 Fluxer Contributors
*
* This file is part of Fluxer.
*
* Fluxer is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Fluxer is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Fluxer. If not, see <https://www.gnu.org/licenses/>.
*/
import {MS_PER_DAY, MS_PER_HOUR, MS_PER_MINUTE, MS_PER_SECOND} from '@fluxer/date_utils/src/DateConstants';
import {parseDate} from '@fluxer/date_utils/src/DateParsing';
import type {DateInput} from '@fluxer/date_utils/src/DateTypes';
export function isSameDay(date1: DateInput, date2?: DateInput): boolean {
const d1 = parseDate(date1);
const d2 = date2 != null ? parseDate(date2) : new Date();
return d1.getFullYear() === d2.getFullYear() && d1.getMonth() === d2.getMonth() && d1.getDate() === d2.getDate();
}
export function isYesterday(date: DateInput, now?: Date): boolean {
const nowDate = now ?? new Date();
const yesterday = new Date(nowDate);
yesterday.setDate(yesterday.getDate() - 1);
return isSameDay(date, yesterday);
}
export function getDaysBetween(date1: DateInput, date2: DateInput): number {
const d1 = parseDate(date1);
const d2 = parseDate(date2);
const d1Start = new Date(d1.getFullYear(), d1.getMonth(), d1.getDate());
const d2Start = new Date(d2.getFullYear(), d2.getMonth(), d2.getDate());
return Math.round((d1Start.getTime() - d2Start.getTime()) / MS_PER_DAY);
}
export function getDaysDiff(date1: DateInput, date2: DateInput): number {
return Math.floor((parseDate(date1).getTime() - parseDate(date2).getTime()) / MS_PER_DAY);
}
export function getHoursDiff(date1: DateInput, date2: DateInput): number {
return Math.floor((parseDate(date1).getTime() - parseDate(date2).getTime()) / MS_PER_HOUR);
}
export function getMinutesDiff(date1: DateInput, date2: DateInput): number {
return Math.floor((parseDate(date1).getTime() - parseDate(date2).getTime()) / MS_PER_MINUTE);
}
export function getSecondsDiff(date1: DateInput, date2: DateInput): number {
return Math.floor((parseDate(date1).getTime() - parseDate(date2).getTime()) / MS_PER_SECOND);
}

View File

@@ -0,0 +1,36 @@
/*
* Copyright (C) 2026 Fluxer Contributors
*
* This file is part of Fluxer.
*
* Fluxer is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Fluxer is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Fluxer. If not, see <https://www.gnu.org/licenses/>.
*/
import {Locales} from '@fluxer/constants/src/Locales';
export const DEFAULT_LOCALE = Locales.EN_US;
export const MS_PER_SECOND = 1000;
export const SECONDS_PER_MINUTE = 60;
export const MINUTES_PER_HOUR = 60;
export const HOURS_PER_DAY = 24;
export const DAYS_PER_WEEK = 7;
export const DAYS_PER_MONTH = 30;
export const DAYS_PER_YEAR = 365;
export const MS_PER_MINUTE = SECONDS_PER_MINUTE * MS_PER_SECOND;
export const MS_PER_HOUR = MINUTES_PER_HOUR * MS_PER_MINUTE;
export const MS_PER_DAY = HOURS_PER_DAY * MS_PER_HOUR;
export const SECONDS_PER_HOUR = MINUTES_PER_HOUR * SECONDS_PER_MINUTE;
export const SECONDS_PER_DAY = HOURS_PER_DAY * SECONDS_PER_HOUR;

View File

@@ -0,0 +1,76 @@
/*
* Copyright (C) 2026 Fluxer Contributors
*
* This file is part of Fluxer.
*
* Fluxer is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Fluxer is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Fluxer. If not, see <https://www.gnu.org/licenses/>.
*/
import {
DAYS_PER_MONTH,
DAYS_PER_WEEK,
DAYS_PER_YEAR,
HOURS_PER_DAY,
MINUTES_PER_HOUR,
SECONDS_PER_HOUR,
SECONDS_PER_MINUTE,
} from '@fluxer/date_utils/src/DateConstants';
import {parseDate} from '@fluxer/date_utils/src/DateParsing';
import type {DateInput} from '@fluxer/date_utils/src/DateTypes';
export function formatDuration(seconds: number): string {
if (!Number.isFinite(seconds) || seconds < 0) {
return '0:00';
}
const hours = Math.floor(seconds / SECONDS_PER_HOUR);
const minutes = Math.floor((seconds % SECONDS_PER_HOUR) / SECONDS_PER_MINUTE);
const secs = Math.floor(seconds % SECONDS_PER_MINUTE);
if (hours > 0) {
return `${hours}:${minutes.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
}
return `${minutes}:${secs.toString().padStart(2, '0')}`;
}
export function formatShortRelativeTime(timestamp: DateInput, minUnit: '1m' | 'now' = 'now'): string {
const date = parseDate(timestamp);
const now = new Date();
const diffMs = date.getTime() - now.getTime();
const diffSeconds = Math.floor(diffMs / 1000);
const diffMinutes = Math.floor(diffSeconds / SECONDS_PER_MINUTE);
const diffHours = Math.floor(diffMinutes / MINUTES_PER_HOUR);
const diffDays = Math.floor(diffHours / HOURS_PER_DAY);
if (Math.abs(diffSeconds) < SECONDS_PER_MINUTE) {
return minUnit === '1m' ? '1m' : 'now';
}
if (Math.abs(diffMinutes) < MINUTES_PER_HOUR) {
return `${Math.abs(diffMinutes)}m`;
}
if (Math.abs(diffHours) < HOURS_PER_DAY) {
return `${Math.abs(diffHours)}h`;
}
if (Math.abs(diffDays) < DAYS_PER_WEEK) {
return `${Math.abs(diffDays)}d`;
}
if (Math.abs(diffDays) < DAYS_PER_MONTH) {
return `${Math.floor(Math.abs(diffDays) / DAYS_PER_WEEK)}w`;
}
if (Math.abs(diffDays) < DAYS_PER_YEAR) {
return `${Math.floor(Math.abs(diffDays) / DAYS_PER_MONTH)}mo`;
}
return `${Math.floor(Math.abs(diffDays) / DAYS_PER_YEAR)}y`;
}

View File

@@ -0,0 +1,35 @@
/*
* Copyright (C) 2026 Fluxer Contributors
*
* This file is part of Fluxer.
*
* Fluxer is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Fluxer is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Fluxer. If not, see <https://www.gnu.org/licenses/>.
*/
const formatterCache = new Map<string, Intl.DateTimeFormat>();
function buildCacheKey(locale: string, options: Intl.DateTimeFormatOptions): string {
return `${locale}:${JSON.stringify(options)}`;
}
export function getDateFormatter(locale: string, options: Intl.DateTimeFormatOptions = {}): Intl.DateTimeFormat {
const key = buildCacheKey(locale, options);
const cached = formatterCache.get(key);
if (cached !== undefined) {
return cached;
}
const formatter = new Intl.DateTimeFormat(locale, options);
formatterCache.set(key, formatter);
return formatter;
}

View File

@@ -0,0 +1,215 @@
/*
* Copyright (C) 2026 Fluxer Contributors
*
* This file is part of Fluxer.
*
* Fluxer is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Fluxer is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Fluxer. If not, see <https://www.gnu.org/licenses/>.
*/
import {isSameDay} from '@fluxer/date_utils/src/DateComparison';
import {DEFAULT_LOCALE} from '@fluxer/date_utils/src/DateConstants';
import {getDateFormatter} from '@fluxer/date_utils/src/DateFormatterCache';
import {localeUses12Hour} from '@fluxer/date_utils/src/DateHourCycle';
import {parseDate} from '@fluxer/date_utils/src/DateParsing';
import type {DateInput} from '@fluxer/date_utils/src/DateTypes';
function resolveHour12(locale: string, hour12?: boolean): boolean {
return hour12 ?? localeUses12Hour(locale);
}
export function formatDate(
date: DateInput,
options: Intl.DateTimeFormatOptions = {
year: 'numeric',
month: 'short',
day: 'numeric',
hour: 'numeric',
minute: '2-digit',
},
locale: string = DEFAULT_LOCALE,
): string {
const dateObj = parseDate(date);
if (Number.isNaN(dateObj.getTime())) {
return String(date);
}
return getDateFormatter(locale, options).format(dateObj);
}
export function formatTimestamp(
timestamp: string,
locale: string = DEFAULT_LOCALE,
options: Intl.DateTimeFormatOptions = {
year: 'numeric',
month: 'short',
day: 'numeric',
hour: 'numeric',
minute: '2-digit',
},
): string {
const date = parseDate(timestamp);
if (Number.isNaN(date.getTime())) {
return timestamp;
}
return getDateFormatter(locale, options).format(date);
}
export function getFormattedDateTime(timestamp: DateInput, locale: string = DEFAULT_LOCALE, hour12?: boolean): string {
const date = parseDate(timestamp);
return getDateFormatter(locale, {
month: 'numeric',
day: 'numeric',
year: 'numeric',
hour: 'numeric',
minute: '2-digit',
hour12: resolveHour12(locale, hour12),
}).format(date);
}
export function getFormattedDateTimeInZone(
isoString: string,
timezone: string,
locale: string = DEFAULT_LOCALE,
hour12?: boolean,
): string {
try {
const date = new Date(isoString);
if (Number.isNaN(date.getTime())) {
return isoString;
}
return getDateFormatter(locale, {
month: 'short',
day: 'numeric',
year: 'numeric',
hour: 'numeric',
minute: '2-digit',
hour12: resolveHour12(locale, hour12),
timeZone: timezone,
}).format(date);
} catch {
return isoString;
}
}
export function getFormattedShortDate(timestamp: DateInput, locale: string = DEFAULT_LOCALE): string {
return getDateFormatter(locale, {month: 'short', day: 'numeric', year: 'numeric'}).format(parseDate(timestamp));
}
export function getFormattedLongDate(timestamp: DateInput, locale: string = DEFAULT_LOCALE): string {
return getDateFormatter(locale, {month: 'long', day: 'numeric', year: 'numeric'}).format(parseDate(timestamp));
}
export function getFormattedTime(timestamp: DateInput, locale: string = DEFAULT_LOCALE, hour12?: boolean): string {
return getDateFormatter(locale, {
hour: 'numeric',
minute: '2-digit',
hour12: resolveHour12(locale, hour12),
}).format(parseDate(timestamp));
}
export function getFormattedCompactDateTime(
timestamp: DateInput,
locale: string = DEFAULT_LOCALE,
hour12?: boolean,
): string {
const date = parseDate(timestamp);
const datePart = getDateFormatter('en-US', {month: 'numeric', day: 'numeric', year: '2-digit'}).format(date);
const timePart = getDateFormatter(locale, {
hour: 'numeric',
minute: '2-digit',
hour12: resolveHour12(locale, hour12),
}).format(date);
return `${datePart}, ${timePart}`;
}
export function getFormattedFullDate(timestamp: DateInput, locale: string = DEFAULT_LOCALE): string {
return getDateFormatter(locale, {
weekday: 'long',
month: 'long',
day: 'numeric',
year: 'numeric',
}).format(parseDate(timestamp));
}
export function getFormattedDateTimeWithSeconds(
timestamp: DateInput,
locale: string = DEFAULT_LOCALE,
hour12?: boolean,
): string {
const date = parseDate(timestamp);
const use12Hour = resolveHour12(locale, hour12);
const datePart = getDateFormatter(locale, {
weekday: 'long',
month: 'long',
day: 'numeric',
year: 'numeric',
}).format(date);
const timePart = getDateFormatter(locale, {
hour: 'numeric',
minute: '2-digit',
second: '2-digit',
hour12: use12Hour,
}).format(date);
return `${datePart} ${timePart}`;
}
export function getRelativeDateString(
timestamp: DateInput,
locale: string = DEFAULT_LOCALE,
hour12?: boolean,
now?: Date,
): string {
const date = parseDate(timestamp);
const nowDate = now ?? new Date();
const use12Hour = resolveHour12(locale, hour12);
const timeString = getDateFormatter(locale, {
hour: 'numeric',
minute: '2-digit',
hour12: use12Hour,
}).format(date);
if (isSameDay(date, nowDate)) {
return `Today at ${timeString}`;
}
const yesterday = new Date(nowDate);
yesterday.setDate(yesterday.getDate() - 1);
if (isSameDay(date, yesterday)) {
return `Yesterday at ${timeString}`;
}
return getDateFormatter(locale, {
month: 'numeric',
day: 'numeric',
year: 'numeric',
hour: 'numeric',
minute: '2-digit',
hour12: use12Hour,
}).format(date);
}
export function formatLastActive(date: DateInput, locale: string = DEFAULT_LOCALE): string {
const dateObj = parseDate(date);
if (Number.isNaN(dateObj.getTime())) {
return String(date);
}
return getDateFormatter(locale, {dateStyle: 'medium', timeStyle: 'short'}).format(dateObj);
}
export function formatScheduledMessage(date: DateInput, locale: string = DEFAULT_LOCALE, timeZone?: string): string {
const dateObj = parseDate(date);
if (Number.isNaN(dateObj.getTime())) {
return String(date);
}
return getDateFormatter(locale, {dateStyle: 'medium', timeStyle: 'short', timeZone}).format(dateObj);
}

View File

@@ -0,0 +1,43 @@
/*
* Copyright (C) 2026 Fluxer Contributors
*
* This file is part of Fluxer.
*
* Fluxer is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Fluxer is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Fluxer. If not, see <https://www.gnu.org/licenses/>.
*/
const TWELVE_HOUR_LOCALES = [
'en-us',
'en-ca',
'en-au',
'en-nz',
'en-ph',
'en-in',
'en-pk',
'en-bd',
'en-za',
'es-mx',
'es-co',
'ar',
'hi',
'bn',
'ur',
'fil',
'tl',
];
export function localeUses12Hour(locale: string): boolean {
const lang = locale.toLowerCase();
return TWELVE_HOUR_LOCALES.some((l) => lang.startsWith(l));
}

View File

@@ -0,0 +1,55 @@
/*
* Copyright (C) 2026 Fluxer Contributors
*
* This file is part of Fluxer.
*
* Fluxer is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Fluxer is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Fluxer. If not, see <https://www.gnu.org/licenses/>.
*/
import {getDateFormatter} from '@fluxer/date_utils/src/DateFormatterCache';
import type {DateFieldType} from '@fluxer/date_utils/src/DateTypes';
export function getSystemTimeZone(): string {
return Intl.DateTimeFormat().resolvedOptions().timeZone;
}
export function getDateFieldOrder(locale: string): Array<DateFieldType> {
const formatter = getDateFormatter(locale, {
year: 'numeric',
month: '2-digit',
day: '2-digit',
});
const parts = formatter.formatToParts(new Date(2000, 0, 1));
const order: Array<DateFieldType> = [];
for (const part of parts) {
if (part.type === 'month' && !order.includes('month')) {
order.push('month');
} else if (part.type === 'day' && !order.includes('day')) {
order.push('day');
} else if (part.type === 'year' && !order.includes('year')) {
order.push('year');
}
}
return order;
}
export function getMonthNames(locale: string, format: 'long' | 'short' = 'long'): Array<string> {
return Array.from({length: 12}, (_, index) => {
const monthDate = new Date(2000, index, 1);
return getDateFormatter(locale, {month: format}).format(monthDate);
});
}

View File

@@ -0,0 +1,84 @@
/*
* Copyright (C) 2026 Fluxer Contributors
*
* This file is part of Fluxer.
*
* Fluxer is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Fluxer is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Fluxer. If not, see <https://www.gnu.org/licenses/>.
*/
import type {DateInput} from '@fluxer/date_utils/src/DateTypes';
export function parseDate(input: DateInput): Date {
if (input instanceof Date) {
if (Number.isNaN(input.getTime())) {
return new Date();
}
return input;
}
if (typeof input === 'string') {
const date = new Date(input);
if (Number.isNaN(date.getTime())) {
return new Date();
}
return date;
}
if (input == null || Number.isNaN(input)) {
return new Date();
}
return new Date(input);
}
export function isValidDate(input: DateInput): boolean {
if (input instanceof Date) {
return !Number.isNaN(input.getTime());
}
if (typeof input === 'string') {
return !Number.isNaN(new Date(input).getTime());
}
if (typeof input === 'number') {
return !Number.isNaN(input) && Number.isFinite(input);
}
return false;
}
export function extractDatePart(isoString: string): string {
const parts = isoString.split('T');
const datePart = parts[0];
if (datePart) {
return datePart;
}
return isoString;
}
export function extractTimePart(isoString: string): string {
const parts = isoString.split('T');
if (parts.length !== 2) {
return isoString;
}
const timePart = parts[1];
if (!timePart) {
return isoString;
}
let timeClean = timePart.split('.')[0] ?? timePart;
timeClean = timeClean.replace('Z', '');
const timeParts = timeClean.split(':');
if (timeParts.length >= 2) {
const [hour, minute] = timeParts;
return `${hour}:${minute}`;
}
return isoString;
}

View File

@@ -0,0 +1,79 @@
/*
* Copyright (C) 2026 Fluxer Contributors
*
* This file is part of Fluxer.
*
* Fluxer is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Fluxer is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Fluxer. If not, see <https://www.gnu.org/licenses/>.
*/
import {getDateFormatter} from '@fluxer/date_utils/src/DateFormatterCache';
import {localeUses12Hour} from '@fluxer/date_utils/src/DateHourCycle';
import {TimestampStyle} from '@fluxer/markdown_parser/src/types/Enums';
const TIMESTAMP_STYLE_OPTIONS: Record<string, Intl.DateTimeFormatOptions> = {
[TimestampStyle.ShortTime]: {hour: 'numeric', minute: 'numeric'},
[TimestampStyle.LongTime]: {hour: 'numeric', minute: 'numeric', second: 'numeric'},
[TimestampStyle.ShortDate]: {year: 'numeric', month: 'numeric', day: 'numeric'},
[TimestampStyle.LongDate]: {month: 'long', day: 'numeric', year: 'numeric'},
[TimestampStyle.ShortDateTime]: {month: 'long', day: 'numeric', year: 'numeric', hour: 'numeric', minute: 'numeric'},
[TimestampStyle.LongDateTime]: {
weekday: 'long',
month: 'long',
day: 'numeric',
year: 'numeric',
hour: 'numeric',
minute: 'numeric',
},
[TimestampStyle.ShortDateShortTime]: {
month: 'numeric',
day: 'numeric',
year: 'numeric',
hour: 'numeric',
minute: 'numeric',
},
[TimestampStyle.ShortDateMediumTime]: {
month: 'numeric',
day: 'numeric',
year: 'numeric',
hour: 'numeric',
minute: 'numeric',
second: 'numeric',
},
};
const DEFAULT_STYLE_OPTIONS: Intl.DateTimeFormatOptions = {
month: 'long',
day: 'numeric',
year: 'numeric',
hour: 'numeric',
minute: 'numeric',
};
const STYLES_WITHOUT_HOUR_CYCLE: ReadonlySet<TimestampStyle> = new Set([
TimestampStyle.ShortDate,
TimestampStyle.LongDate,
]);
export function formatTimestampWithStyle(
timestamp: number,
style: TimestampStyle,
locale: string,
hour12?: boolean,
): string {
const date = new Date(timestamp * 1000);
const baseOptions = TIMESTAMP_STYLE_OPTIONS[style] ?? DEFAULT_STYLE_OPTIONS;
const needsHourCycle = !STYLES_WITHOUT_HOUR_CYCLE.has(style);
const options = needsHourCycle ? {...baseOptions, hour12: hour12 ?? localeUses12Hour(locale)} : baseOptions;
return getDateFormatter(locale, options).format(date);
}

View File

@@ -0,0 +1,28 @@
/*
* Copyright (C) 2026 Fluxer Contributors
*
* This file is part of Fluxer.
*
* Fluxer is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Fluxer is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Fluxer. If not, see <https://www.gnu.org/licenses/>.
*/
export type DateInput = Date | number | string;
export interface DateFormatOptions {
locale?: string;
hour12?: boolean;
timeZone?: string;
}
export type DateFieldType = 'month' | 'day' | 'year';