add explicit type for string-based datetimes, replacing third-party datetime type with internal DateTime type

This commit is contained in:
MaysWind
2025-08-25 00:31:30 +08:00
parent f196ce969b
commit 25681f622d
35 changed files with 423 additions and 404 deletions
@@ -17,7 +17,7 @@ import type { TransactionReconciliationStatementResponseItem } from '@/models/tr
import { isDefined, isArray } from '@/lib/common.ts'; import { isDefined, isArray } from '@/lib/common.ts';
import { sumAmounts } from '@/lib/numeral.ts'; import { sumAmounts } from '@/lib/numeral.ts';
import { import {
getYearAndMonthFromUnixTime, getGregorianCalendarYearAndMonthFromUnixTime,
getYearFirstUnixTimeBySpecifiedUnixTime, getYearFirstUnixTimeBySpecifiedUnixTime,
getQuarterFirstUnixTimeBySpecifiedUnixTime, getQuarterFirstUnixTimeBySpecifiedUnixTime,
getMonthFirstUnixTimeBySpecifiedUnixTime, getMonthFirstUnixTimeBySpecifiedUnixTime,
@@ -99,8 +99,8 @@ export function useAccountBalanceTrendsChartBase(props: CommonAccountBalanceTren
if (!isDefined(props.dateAggregationType)) { if (!isDefined(props.dateAggregationType)) {
return getAllDaysStartAndEndUnixTimes(dataDateRange.value.minUnixTime, dataDateRange.value.maxUnixTime); return getAllDaysStartAndEndUnixTimes(dataDateRange.value.minUnixTime, dataDateRange.value.maxUnixTime);
} else { } else {
const startYearMonth = getYearAndMonthFromUnixTime(dataDateRange.value.minUnixTime); const startYearMonth = getGregorianCalendarYearAndMonthFromUnixTime(dataDateRange.value.minUnixTime);
const endYearMonth = getYearAndMonthFromUnixTime(dataDateRange.value.maxUnixTime); const endYearMonth = getGregorianCalendarYearAndMonthFromUnixTime(dataDateRange.value.maxUnixTime);
return getAllDateRangesByYearMonthRange(startYearMonth, endYearMonth, props.fiscalYearStart, props.dateAggregationType); return getAllDateRangesByYearMonthRange(startYearMonth, endYearMonth, props.fiscalYearStart, props.dateAggregationType);
} }
}); });
+7 -10
View File
@@ -4,9 +4,9 @@ import { type TimeRangeAndDateType, type PresetDateRange, type UnixTimeRange, ty
import { arrangeArrayWithNewStartIndex } from '@/lib/common.ts'; import { arrangeArrayWithNewStartIndex } from '@/lib/common.ts';
import { import {
getCurrentUnixTime, getCurrentUnixTime,
getCurrentYear, getAllowedYearRange,
getUnixTime,
getLocalDatetimeFromUnixTime, getLocalDatetimeFromUnixTime,
getUnixTimeFromLocalDatetime,
getTodayFirstUnixTime, getTodayFirstUnixTime,
getDummyUnixTimeForLocalUsage, getDummyUnixTimeForLocalUsage,
getActualUnixTimeForStore, getActualUnixTimeForStore,
@@ -50,10 +50,7 @@ export function useDateRangeSelectionBase(props: CommonDateRangeSelectionProps)
const userStore = useUserStore(); const userStore = useUserStore();
const { minDate, maxDate } = getDateRangeFromProps(props); const { minDate, maxDate } = getDateRangeFromProps(props);
const yearRange = ref<number[]>([ const yearRange = ref<number[]>(getAllowedYearRange());
2000,
getCurrentYear() + 1
]);
const dateRange = ref<Date[]>([ const dateRange = ref<Date[]>([
getLocalDatetimeFromUnixTime(getDummyUnixTimeForLocalUsage(minDate, getTimezoneOffsetMinutes(), getBrowserTimezoneOffsetMinutes())), getLocalDatetimeFromUnixTime(getDummyUnixTimeForLocalUsage(minDate, getTimezoneOffsetMinutes(), getBrowserTimezoneOffsetMinutes())),
@@ -65,11 +62,11 @@ export function useDateRangeSelectionBase(props: CommonDateRangeSelectionProps)
const isYearFirst = computed<boolean>(() => isLongDateMonthAfterYear()); const isYearFirst = computed<boolean>(() => isLongDateMonthAfterYear());
const is24Hour = computed<boolean>(() => isLongTime24HourFormat()); const is24Hour = computed<boolean>(() => isLongTime24HourFormat());
const beginDateTime = computed<string>(() => { const beginDateTime = computed<string>(() => {
const actualBeginUnixTime = getActualUnixTimeForStore(getUnixTime(dateRange.value[0]), getTimezoneOffsetMinutes(), getBrowserTimezoneOffsetMinutes()); const actualBeginUnixTime = getActualUnixTimeForStore(getUnixTimeFromLocalDatetime(dateRange.value[0]), getTimezoneOffsetMinutes(), getBrowserTimezoneOffsetMinutes());
return formatUnixTimeToLongDateTime(actualBeginUnixTime); return formatUnixTimeToLongDateTime(actualBeginUnixTime);
}); });
const endDateTime = computed<string>(() => { const endDateTime = computed<string>(() => {
const actualEndUnixTime = getActualUnixTimeForStore(getUnixTime(dateRange.value[1]), getTimezoneOffsetMinutes(), getBrowserTimezoneOffsetMinutes()); const actualEndUnixTime = getActualUnixTimeForStore(getUnixTimeFromLocalDatetime(dateRange.value[1]), getTimezoneOffsetMinutes(), getBrowserTimezoneOffsetMinutes());
return formatUnixTimeToLongDateTime(actualEndUnixTime); return formatUnixTimeToLongDateTime(actualEndUnixTime);
}); });
const presetRanges = computed<PresetDateRange[]>(() => { const presetRanges = computed<PresetDateRange[]>(() => {
@@ -108,8 +105,8 @@ export function useDateRangeSelectionBase(props: CommonDateRangeSelectionProps)
const currentMinDate = dateRange.value[0]; const currentMinDate = dateRange.value[0];
const currentMaxDate = dateRange.value[1]; const currentMaxDate = dateRange.value[1];
let minUnixTime = getUnixTime(currentMinDate); let minUnixTime = getUnixTimeFromLocalDatetime(currentMinDate);
let maxUnixTime = getUnixTime(currentMaxDate); let maxUnixTime = getUnixTimeFromLocalDatetime(currentMaxDate);
if (minUnixTime < 0 || maxUnixTime < 0) { if (minUnixTime < 0 || maxUnixTime < 0) {
throw new Error('Date is too early'); throw new Error('Date is too early');
+2 -5
View File
@@ -7,7 +7,7 @@ import { useUserStore } from '@/stores/user.ts';
import { type NameValue } from '@/core/base.ts'; import { type NameValue } from '@/core/base.ts';
import { type WeekDayValue } from '@/core/datetime.ts'; import { type WeekDayValue } from '@/core/datetime.ts';
import { arrangeArrayWithNewStartIndex } from '@/lib/common.ts'; import { arrangeArrayWithNewStartIndex } from '@/lib/common.ts';
import { getCurrentYear } from '@/lib/datetime.ts'; import { getAllowedYearRange } from '@/lib/datetime.ts';
export interface TimePickerValue { export interface TimePickerValue {
value: string; value: string;
@@ -34,10 +34,7 @@ export function useDateTimeSelectionBase() {
const isSecondTwoDigits = ref<boolean>(isLongTimeSecondTwoDigits()); const isSecondTwoDigits = ref<boolean>(isLongTimeSecondTwoDigits());
const isMeridiemIndicatorFirst = ref<boolean>(isLongTimeMeridiemIndicatorFirst() || false); const isMeridiemIndicatorFirst = ref<boolean>(isLongTimeMeridiemIndicatorFirst() || false);
const yearRange = ref<number[]>([ const yearRange = ref<number[]>(getAllowedYearRange());
2000,
getCurrentYear() + 1
]);
const meridiemItems = computed<NameValue[]>(() => getAllMeridiemIndicators()); const meridiemItems = computed<NameValue[]>(() => getAllMeridiemIndicators());
@@ -41,7 +41,7 @@ function getFiscalYearStartFromProps(props: CommonFiscalYearStartSelectionProps)
export function useFiscalYearStartSelectionBase(props: CommonFiscalYearStartSelectionProps) { export function useFiscalYearStartSelectionBase(props: CommonFiscalYearStartSelectionProps) {
const { const {
getAllMinWeekdayNames, getAllMinWeekdayNames,
formatMonthDayToLongDay formatGregorianCalendarMonthDashDayToLongMonthDay
} = useI18n(); } = useI18n();
const userStore = useUserStore(); const userStore = useUserStore();
@@ -81,7 +81,7 @@ export function useFiscalYearStartSelectionBase(props: CommonFiscalYearStartSele
fiscalYearStart = FiscalYearStart.Default; fiscalYearStart = FiscalYearStart.Default;
} }
return formatMonthDayToLongDay(fiscalYearStart.toMonthDashDayString()); return formatGregorianCalendarMonthDashDayToLongMonthDay(fiscalYearStart.toMonthDashDayString());
}); });
const allowedMinDate = computed<Date>(() => getLocalDatetimeFromUnixTime(getThisYearFirstUnixTime())); const allowedMinDate = computed<Date>(() => getLocalDatetimeFromUnixTime(getThisYearFirstUnixTime()));
+7 -11
View File
@@ -1,13 +1,13 @@
import { ref, computed } from 'vue'; import { ref, computed } from 'vue';
import type { Year0BasedMonth } from '@/core/datetime.ts'; import type { TextualYearMonth, Year0BasedMonth } from '@/core/datetime.ts';
import { import {
getYear0BasedMonthObjectFromUnixTime, getYear0BasedMonthObjectFromUnixTime,
getYear0BasedMonthObjectFromString, getYear0BasedMonthObjectFromString,
getYearMonthStringFromYear0BasedMonthObject, getYearMonthStringFromYear0BasedMonthObject,
getCurrentUnixTime, getCurrentUnixTime,
getCurrentYear, getAllowedYearRange,
getThisYearFirstUnixTime, getThisYearFirstUnixTime,
getYearMonthFirstUnixTime, getYearMonthFirstUnixTime,
getYearMonthLastUnixTime getYearMonthLastUnixTime
@@ -21,8 +21,8 @@ export interface MonthSelectionValue {
} }
export interface CommonMonthRangeSelectionProps { export interface CommonMonthRangeSelectionProps {
minTime?: string; minTime?: TextualYearMonth;
maxTime?: string; maxTime?: TextualYearMonth;
title?: string; title?: string;
hint?: string; hint?: string;
show: boolean; show: boolean;
@@ -64,11 +64,7 @@ export function useMonthRangeSelectionBase(props: CommonMonthRangeSelectionProps
const { formatUnixTimeToLongYearMonth, isLongDateMonthAfterYear } = useI18n(); const { formatUnixTimeToLongYearMonth, isLongDateMonthAfterYear } = useI18n();
const { minDate, maxDate } = getMonthRangeFromProps(props); const { minDate, maxDate } = getMonthRangeFromProps(props);
const yearRange = ref<number[]>([ const yearRange = ref<number[]>(getAllowedYearRange());
2000,
getCurrentYear() + 1
]);
const dateRange = ref<MonthSelectionValue[]>([ const dateRange = ref<MonthSelectionValue[]>([
minDate, minDate,
maxDate maxDate
@@ -84,7 +80,7 @@ export function useMonthRangeSelectionBase(props: CommonMonthRangeSelectionProps
month0base: dateRange.value[1].month month0base: dateRange.value[1].month
}))); })));
function getMonthSelectionValue(yearMonth: string): MonthSelectionValue | null { function getMonthSelectionValue(yearMonth: TextualYearMonth): MonthSelectionValue | null {
const yearMonthObj = getYear0BasedMonthObjectFromString(yearMonth); const yearMonthObj = getYear0BasedMonthObjectFromString(yearMonth);
if (!yearMonthObj) { if (!yearMonthObj) {
@@ -97,7 +93,7 @@ export function useMonthRangeSelectionBase(props: CommonMonthRangeSelectionProps
}; };
} }
function getFinalMonthRange(): { minYearMonth: string, maxYearMonth: string } | null { function getFinalMonthRange(): { minYearMonth: TextualYearMonth | '', maxYearMonth: TextualYearMonth | '' } | null {
if (!dateRange.value[0] || !dateRange.value[1]) { if (!dateRange.value[0] || !dateRange.value[1]) {
return null; return null;
} }
+12 -24
View File
@@ -4,9 +4,7 @@ import type { Year0BasedMonth } from '@/core/datetime.ts';
import { import {
getYear0BasedMonthObjectFromUnixTime, getYear0BasedMonthObjectFromUnixTime,
getYear0BasedMonthObjectFromString, getAllowedYearRange,
getYearMonthStringFromYear0BasedMonthObject,
getCurrentYear,
getThisMonthFirstUnixTime getThisMonthFirstUnixTime
} from '@/lib/datetime.ts'; } from '@/lib/datetime.ts';
@@ -18,7 +16,7 @@ export interface MonthSelectionValue {
} }
export interface CommonMonthSelectionProps { export interface CommonMonthSelectionProps {
modelValue?: string; modelValue?: Year0BasedMonth;
title?: string; title?: string;
hint?: string; hint?: string;
show: boolean; show: boolean;
@@ -28,11 +26,7 @@ function getYearMonthValueFromProps(props: CommonMonthSelectionProps): MonthSele
let value: Year0BasedMonth = getYear0BasedMonthObjectFromUnixTime(getThisMonthFirstUnixTime()); let value: Year0BasedMonth = getYear0BasedMonthObjectFromUnixTime(getThisMonthFirstUnixTime());
if (props.modelValue) { if (props.modelValue) {
const yearMonth = getYear0BasedMonthObjectFromString(props.modelValue); value = props.modelValue;
if (yearMonth) {
value = yearMonth;
}
} }
return { return {
@@ -44,29 +38,23 @@ function getYearMonthValueFromProps(props: CommonMonthSelectionProps): MonthSele
export function useMonthSelectionBase(props: CommonMonthSelectionProps) { export function useMonthSelectionBase(props: CommonMonthSelectionProps) {
const { isLongDateMonthAfterYear } = useI18n(); const { isLongDateMonthAfterYear } = useI18n();
const yearRange = ref<number[]>([ const yearRange = ref<number[]>(getAllowedYearRange());
2000,
getCurrentYear() + 1
]);
const monthValue = ref<MonthSelectionValue>(getYearMonthValueFromProps(props)); const monthValue = ref<MonthSelectionValue>(getYearMonthValueFromProps(props));
const isYearFirst = computed<boolean>(() => isLongDateMonthAfterYear()); const isYearFirst = computed<boolean>(() => isLongDateMonthAfterYear());
function getMonthSelectionValue(yearMonth: string): MonthSelectionValue | null { function getMonthSelectionValue(yearMonth: Year0BasedMonth): MonthSelectionValue | null {
const yearMonthObj = getYear0BasedMonthObjectFromString(yearMonth); if (!yearMonth) {
if (!yearMonthObj) {
return null; return null;
} }
return { return {
year: yearMonthObj.year, year: yearMonth.year,
month: yearMonthObj.month0base month: yearMonth.month0base
}; };
} }
function getTextualYearMonth(): string | null { function getYear0BasedMonth(): Year0BasedMonth | null {
if (!monthValue.value) { if (!monthValue.value) {
return null; return null;
} }
@@ -75,10 +63,10 @@ export function useMonthSelectionBase(props: CommonMonthSelectionProps) {
throw new Error('Date is too early'); throw new Error('Date is too early');
} }
return getYearMonthStringFromYear0BasedMonthObject({ return {
year: monthValue.value.year, year: monthValue.value.year,
month0base: monthValue.value.month month0base: monthValue.value.month
}); };
} }
return { return {
@@ -89,6 +77,6 @@ export function useMonthSelectionBase(props: CommonMonthSelectionProps) {
isYearFirst, isYearFirst,
// functions // functions
getMonthSelectionValue, getMonthSelectionValue,
getTextualYearMonth getYear0BasedMonth
}; };
} }
@@ -3,6 +3,7 @@ import { computed } from 'vue';
import { useI18n } from '@/locales/helpers.ts'; import { useI18n } from '@/locales/helpers.ts';
import type { import type {
TextualYearMonth,
Year1BasedMonth, Year1BasedMonth,
TimeRangeAndDateType, TimeRangeAndDateType,
YearUnixTime, YearUnixTime,
@@ -18,8 +19,8 @@ import { getAllDateRangesFromItems } from '@/lib/statistics.ts';
export interface CommonMonthlyTrendsChartProps<T extends Year1BasedMonth> { export interface CommonMonthlyTrendsChartProps<T extends Year1BasedMonth> {
items: YearMonthItems<T>[]; items: YearMonthItems<T>[];
startYearMonth: string; startYearMonth: TextualYearMonth | '';
endYearMonth: string; endYearMonth: TextualYearMonth | '';
fiscalYearStart: number; fiscalYearStart: number;
sortingType: number; sortingType: number;
dateAggregationType: number; dateAggregationType: number;
+8 -11
View File
@@ -44,13 +44,13 @@ import { useI18n } from '@/locales/helpers.ts';
import { useUserStore } from '@/stores/user.ts'; import { useUserStore } from '@/stores/user.ts';
import { type WeekDayValue } from '@/core/datetime.ts'; import { type TextualYearMonthDay, type WeekDayValue } from '@/core/datetime.ts';
import { ThemeType } from '@/core/theme.ts'; import { ThemeType } from '@/core/theme.ts';
import { arrangeArrayWithNewStartIndex } from '@/lib/common.ts'; import { arrangeArrayWithNewStartIndex } from '@/lib/common.ts';
import { getCurrentYear } from '@/lib/datetime.ts'; import { getAllowedYearRange } from '@/lib/datetime.ts';
const props = defineProps<{ const props = defineProps<{
modelValue?: string; modelValue?: TextualYearMonthDay;
disabled?: boolean; disabled?: boolean;
readonly?: boolean; readonly?: boolean;
clearable?: boolean; clearable?: boolean;
@@ -59,22 +59,19 @@ const props = defineProps<{
}>(); }>();
const emit = defineEmits<{ const emit = defineEmits<{
(e: 'update:modelValue', value: string): void; (e: 'update:modelValue', value: TextualYearMonthDay): void;
}>(); }>();
const theme = useTheme(); const theme = useTheme();
const { tt, getAllMinWeekdayNames, getMonthShortName, formatDateToLongDate, isLongDateMonthAfterYear } = useI18n(); const { tt, getAllMinWeekdayNames, getMonthShortName, formatGregorianCalendarYearDashMonthDashDayToLongDate, isLongDateMonthAfterYear } = useI18n();
const userStore = useUserStore(); const userStore = useUserStore();
const yearRange = ref<number[]>([ const yearRange = ref<number[]>(getAllowedYearRange());
2000,
getCurrentYear() + 1
]);
const dateTime = computed<string>({ const dateTime = computed<string>({
get: () => props.modelValue ?? '', get: () => props.modelValue ?? '',
set: (value: string) => emit('update:modelValue', value) set: (value: string) => emit('update:modelValue', value as TextualYearMonthDay)
}); });
const isDarkMode = computed<boolean>(() => theme.global.name.value === ThemeType.Dark); const isDarkMode = computed<boolean>(() => theme.global.name.value === ThemeType.Dark);
@@ -83,7 +80,7 @@ const dayNames = computed<string[]>(() => arrangeArrayWithNewStartIndex(getAllMi
const isYearFirst = computed<boolean>(() => isLongDateMonthAfterYear()); const isYearFirst = computed<boolean>(() => isLongDateMonthAfterYear());
const displayTime = computed<string>(() => { const displayTime = computed<string>(() => {
if (props.modelValue) { if (props.modelValue) {
return formatDateToLongDate(props.modelValue); return formatGregorianCalendarYearDashMonthDashDayToLongDate(props.modelValue);
} else if (props.noDataText) { } else if (props.noDataText) {
return props.noDataText; return props.noDataText;
} else { } else {
+3 -3
View File
@@ -105,7 +105,7 @@ import {
getBrowserTimezoneOffsetMinutes, getBrowserTimezoneOffsetMinutes,
getLocalDatetimeFromUnixTime, getLocalDatetimeFromUnixTime,
getActualUnixTimeForStore, getActualUnixTimeForStore,
getUnixTime, getUnixTimeFromLocalDatetime,
getAMOrPM, getAMOrPM,
getCombinedDateAndTimeValues getCombinedDateAndTimeValues
} from '@/lib/datetime.ts'; } from '@/lib/datetime.ts';
@@ -154,7 +154,7 @@ const dateTime = computed<Date>({
return getLocalDatetimeFromUnixTime(props.modelValue); return getLocalDatetimeFromUnixTime(props.modelValue);
}, },
set: (value: Date) => { set: (value: Date) => {
const unixTime = getUnixTime(value); const unixTime = getUnixTimeFromLocalDatetime(value);
if (unixTime < 0) { if (unixTime < 0) {
emit('error', 'Date is too early'); emit('error', 'Date is too early');
@@ -225,7 +225,7 @@ const currentSecond = computed<string>({
}); });
const isDarkMode = computed<boolean>(() => theme.global.name.value === ThemeType.Dark); const isDarkMode = computed<boolean>(() => theme.global.name.value === ThemeType.Dark);
const displayTime = computed<string>(() => formatUnixTimeToLongDateTime(getActualUnixTimeForStore(getUnixTime(dateTime.value), getTimezoneOffsetMinutes(), getBrowserTimezoneOffsetMinutes()))); const displayTime = computed<string>(() => formatUnixTimeToLongDateTime(getActualUnixTimeForStore(getUnixTimeFromLocalDatetime(dateTime.value), getTimezoneOffsetMinutes(), getBrowserTimezoneOffsetMinutes())));
function toggleMeridiemIndicator(): void { function toggleMeridiemIndicator(): void {
if (currentMeridiemIndicator.value === MeridiemIndicator.AM.name) { if (currentMeridiemIndicator.value === MeridiemIndicator.AM.name) {
@@ -71,6 +71,7 @@ import { useI18n } from '@/locales/helpers.ts';
import { type CommonMonthRangeSelectionProps, useMonthRangeSelectionBase } from '@/components/base/MonthRangeSelectionBase.ts'; import { type CommonMonthRangeSelectionProps, useMonthRangeSelectionBase } from '@/components/base/MonthRangeSelectionBase.ts';
import { ThemeType } from '@/core/theme.ts'; import { ThemeType } from '@/core/theme.ts';
import { type TextualYearMonth } from '@/core/datetime.ts';
interface DesktopMonthRangeSelectionProps extends CommonMonthRangeSelectionProps { interface DesktopMonthRangeSelectionProps extends CommonMonthRangeSelectionProps {
persistent?: boolean; persistent?: boolean;
@@ -79,7 +80,7 @@ interface DesktopMonthRangeSelectionProps extends CommonMonthRangeSelectionProps
const props = defineProps<DesktopMonthRangeSelectionProps>(); const props = defineProps<DesktopMonthRangeSelectionProps>();
const emit = defineEmits<{ const emit = defineEmits<{
(e: 'update:show', value: boolean): void; (e: 'update:show', value: boolean): void;
(e: 'dateRange:change', minYearMonth: string, maxYearMonth: string): void; (e: 'dateRange:change', minYearMonth: TextualYearMonth | '', maxYearMonth: TextualYearMonth | ''): void;
(e: 'error', message: string): void; (e: 'error', message: string): void;
}>(); }>();
@@ -50,6 +50,7 @@ import { useI18n } from '@/locales/helpers.ts';
import { type CommonMonthSelectionProps, useMonthSelectionBase } from '@/components/base/MonthSelectionBase.ts'; import { type CommonMonthSelectionProps, useMonthSelectionBase } from '@/components/base/MonthSelectionBase.ts';
import { ThemeType } from '@/core/theme.ts'; import { ThemeType } from '@/core/theme.ts';
import type { Year0BasedMonth } from '@/core/datetime.ts';
interface DesktopMonthSelectionProps extends CommonMonthSelectionProps { interface DesktopMonthSelectionProps extends CommonMonthSelectionProps {
persistent?: boolean; persistent?: boolean;
@@ -57,7 +58,7 @@ interface DesktopMonthSelectionProps extends CommonMonthSelectionProps {
const props = defineProps<DesktopMonthSelectionProps>(); const props = defineProps<DesktopMonthSelectionProps>();
const emit = defineEmits<{ const emit = defineEmits<{
(e: 'update:modelValue', value: string): void; (e: 'update:modelValue', value: Year0BasedMonth): void;
(e: 'update:show', value: boolean): void; (e: 'update:show', value: boolean): void;
(e: 'error', message: string): void; (e: 'error', message: string): void;
}>(); }>();
@@ -65,7 +66,7 @@ const emit = defineEmits<{
const theme = useTheme(); const theme = useTheme();
const { tt, getMonthShortName } = useI18n(); const { tt, getMonthShortName } = useI18n();
const { yearRange, monthValue, isYearFirst, getMonthSelectionValue, getTextualYearMonth } = useMonthSelectionBase(props); const { yearRange, monthValue, isYearFirst, getMonthSelectionValue, getYear0BasedMonth } = useMonthSelectionBase(props);
const isDarkMode = computed<boolean>(() => theme.global.name.value === ThemeType.Dark); const isDarkMode = computed<boolean>(() => theme.global.name.value === ThemeType.Dark);
const showState = computed<boolean>({ const showState = computed<boolean>({
@@ -75,7 +76,7 @@ const showState = computed<boolean>({
function confirm(): void { function confirm(): void {
try { try {
const finalMonthRange = getTextualYearMonth(); const finalMonthRange = getYear0BasedMonth();
if (!finalMonthRange) { if (!finalMonthRange) {
return; return;
+6 -9
View File
@@ -45,17 +45,17 @@ import { useI18n } from '@/locales/helpers.ts';
import { useEnvironmentsStore } from '@/stores/environment.ts'; import { useEnvironmentsStore } from '@/stores/environment.ts';
import { useUserStore } from '@/stores/user.ts'; import { useUserStore } from '@/stores/user.ts';
import { type WeekDayValue } from '@/core/datetime.ts'; import { type TextualYearMonthDay, type WeekDayValue } from '@/core/datetime.ts';
import { arrangeArrayWithNewStartIndex } from '@/lib/common.ts'; import { arrangeArrayWithNewStartIndex } from '@/lib/common.ts';
import { getCurrentYear } from '@/lib/datetime.ts'; import { getAllowedYearRange } from '@/lib/datetime.ts';
const props = defineProps<{ const props = defineProps<{
modelValue?: string; modelValue?: TextualYearMonthDay;
show: boolean; show: boolean;
}>(); }>();
const emit = defineEmits<{ const emit = defineEmits<{
(e: 'update:modelValue', value: string): void; (e: 'update:modelValue', value: TextualYearMonthDay): void;
(e: 'update:show', value: boolean): void; (e: 'update:show', value: boolean): void;
}>(); }>();
@@ -64,10 +64,7 @@ const { tt, getAllMinWeekdayNames, getMonthShortName, isLongDateMonthAfterYear }
const environmentsStore = useEnvironmentsStore(); const environmentsStore = useEnvironmentsStore();
const userStore = useUserStore(); const userStore = useUserStore();
const yearRange = ref<number[]>([ const yearRange = ref<number[]>(getAllowedYearRange());
2000,
getCurrentYear() + 1
]);
const dateTime = ref<string>(''); const dateTime = ref<string>('');
const isDarkMode = computed<boolean>(() => environmentsStore.framework7DarkMode || false); const isDarkMode = computed<boolean>(() => environmentsStore.framework7DarkMode || false);
@@ -81,7 +78,7 @@ function clear(): void {
} }
function confirm(): void { function confirm(): void {
emit('update:modelValue', dateTime.value); emit('update:modelValue', dateTime.value as TextualYearMonthDay);
emit('update:show', false); emit('update:show', false);
} }
@@ -132,7 +132,7 @@ import {
getLocalDatetimeFromUnixTime, getLocalDatetimeFromUnixTime,
getActualUnixTimeForStore, getActualUnixTimeForStore,
getCurrentUnixTime, getCurrentUnixTime,
getUnixTime, getUnixTimeFromLocalDatetime,
getAMOrPM, getAMOrPM,
getCombinedDateAndTimeValues getCombinedDateAndTimeValues
} from '@/lib/datetime.ts'; } from '@/lib/datetime.ts';
@@ -225,7 +225,7 @@ const currentSecond = computed<string>({
}); });
const isDarkMode = computed<boolean>(() => environmentsStore.framework7DarkMode || false); const isDarkMode = computed<boolean>(() => environmentsStore.framework7DarkMode || false);
const displayTime = computed<string>(() => formatUnixTimeToLongDateTime(getActualUnixTimeForStore(getUnixTime(dateTime.value), getTimezoneOffsetMinutes(), getBrowserTimezoneOffsetMinutes()))); const displayTime = computed<string>(() => formatUnixTimeToLongDateTime(getActualUnixTimeForStore(getUnixTimeFromLocalDatetime(dateTime.value), getTimezoneOffsetMinutes(), getBrowserTimezoneOffsetMinutes())));
const switchButtonTitle = computed<string>(() => mode.value === 'time' ? 'Date' : 'Time'); const switchButtonTitle = computed<string>(() => mode.value === 'time' ? 'Date' : 'Time');
function switchMode(): void { function switchMode(): void {
@@ -249,7 +249,7 @@ function confirm(): void {
return; return;
} }
const unixTime = getUnixTime(dateTime.value); const unixTime = getUnixTimeFromLocalDatetime(dateTime.value);
if (unixTime < 0) { if (unixTime < 0) {
showToast('Date is too early'); showToast('Date is too early');
@@ -52,10 +52,12 @@ import { type CommonMonthRangeSelectionProps, useMonthRangeSelectionBase } from
import { useEnvironmentsStore } from '@/stores/environment.ts'; import { useEnvironmentsStore } from '@/stores/environment.ts';
import { type TextualYearMonth } from '@/core/datetime.ts';
const props = defineProps<CommonMonthRangeSelectionProps>(); const props = defineProps<CommonMonthRangeSelectionProps>();
const emit = defineEmits<{ const emit = defineEmits<{
(e: 'update:show', value: boolean): void; (e: 'update:show', value: boolean): void;
(e: 'dateRange:change', minYearMonth: string, maxYearMonth: string): void; (e: 'dateRange:change', minYearMonth: TextualYearMonth | '', maxYearMonth: TextualYearMonth | ''): void;
}>(); }>();
const { tt, getMonthShortName } = useI18n(); const { tt, getMonthShortName } = useI18n();
@@ -44,17 +44,18 @@ import { useI18n } from '@/locales/helpers.ts';
import { useI18nUIComponents } from '@/lib/ui/mobile.ts'; import { useI18nUIComponents } from '@/lib/ui/mobile.ts';
import { type CommonMonthSelectionProps, useMonthSelectionBase } from '@/components/base/MonthSelectionBase.ts'; import { type CommonMonthSelectionProps, useMonthSelectionBase } from '@/components/base/MonthSelectionBase.ts';
import type { Year0BasedMonth } from '@/core/datetime.ts';
import { useEnvironmentsStore } from '@/stores/environment.ts'; import { useEnvironmentsStore } from '@/stores/environment.ts';
const props = defineProps<CommonMonthSelectionProps>(); const props = defineProps<CommonMonthSelectionProps>();
const emit = defineEmits<{ const emit = defineEmits<{
(e: 'update:modelValue', value: string): void; (e: 'update:modelValue', value: Year0BasedMonth): void;
(e: 'update:show', value: boolean): void; (e: 'update:show', value: boolean): void;
}>(); }>();
const { tt, getMonthShortName } = useI18n(); const { tt, getMonthShortName } = useI18n();
const { showToast } = useI18nUIComponents(); const { showToast } = useI18nUIComponents();
const { yearRange, monthValue, isYearFirst, getMonthSelectionValue, getTextualYearMonth } = useMonthSelectionBase(props); const { yearRange, monthValue, isYearFirst, getMonthSelectionValue, getYear0BasedMonth } = useMonthSelectionBase(props);
const environmentsStore = useEnvironmentsStore(); const environmentsStore = useEnvironmentsStore();
@@ -62,7 +63,7 @@ const isDarkMode = computed<boolean>(() => environmentsStore.framework7DarkMode
function confirm(): void { function confirm(): void {
try { try {
const finalMonthRange = getTextualYearMonth(); const finalMonthRange = getYear0BasedMonth();
if (!finalMonthRange) { if (!finalMonthRange) {
return; return;
+22
View File
@@ -1,5 +1,27 @@
import type { TypeAndName, TypeAndDisplayName } from '@/core/base.ts'; import type { TypeAndName, TypeAndDisplayName } from '@/core/base.ts';
export interface DateTime {
getUnixTime(): number;
getLocalizedCalendarYear(): number;
getGregorianCalendarYear(): number;
getGregorianCalendarQuarter(): number;
getLocalizedCalendarQuarter(): number;
getGregorianCalendarMonth(): number;
getGregorianCalendarMonthName(): string;
getLocalizedCalendarMonth(): number;
getGregorianCalendarDay(): number;
getLocalizedCalendarDay(): number;
getGregorianCalendarYearDashMonthDashDay(): TextualYearMonthDay;
getGregorianCalendarYearDashMonth(): TextualYearMonth;
getWeekDay(): WeekDay;
toGregorianCalendarYearMonthDay(): YearMonthDay;
toGregorianCalendarYear0BasedMonth(): Year0BasedMonth;
format(format: string): string;
}
export type TextualYearMonth = `${number}-${number}`;
export type TextualYearMonthDay = `${number}-${number}-${number}`;
export interface YearQuarter { export interface YearQuarter {
readonly year: number; readonly year: number;
readonly quarter: number; readonly quarter: number;
+3 -3
View File
@@ -1,4 +1,4 @@
import type { UnixTimeRange } from './datetime.ts'; import type { TextualYearMonth, UnixTimeRange } from './datetime.ts';
export class FiscalYearStart { export class FiscalYearStart {
public static readonly JanuaryFirstDay = new FiscalYearStart(1, 1); public static readonly JanuaryFirstDay = new FiscalYearStart(1, 1);
@@ -75,8 +75,8 @@ export class FiscalYearStart {
return FiscalYearStart.of(month, day); return FiscalYearStart.of(month, day);
} }
public toMonthDashDayString(): string { public toMonthDashDayString(): TextualYearMonth {
return `${this.month.toString().padStart(2, '0')}-${this.day.toString().padStart(2, '0')}`; return `${this.month.toString().padStart(2, '0')}-${this.day.toString().padStart(2, '0')}` as TextualYearMonth;
} }
private static isValidFiscalYearMonthDay(month: number, day: number): boolean { private static isValidFiscalYearMonthDay(month: number, day: number): boolean {
+3 -2
View File
@@ -5,6 +5,7 @@ import { describe, expect, test, beforeAll } from '@jest/globals';
import moment from 'moment-timezone'; import moment from 'moment-timezone';
// Import all the fiscal year functions from the lib // Import all the fiscal year functions from the lib
import type { TextualYearMonth } from '@/core/datetime.ts';
import { FiscalYearStart, FiscalYearUnixTime } from '@/core/fiscalyear.ts'; import { FiscalYearStart, FiscalYearUnixTime } from '@/core/fiscalyear.ts';
import { import {
@@ -230,8 +231,8 @@ describe('getFiscalYearTimeRangeFromUnixTime', () => {
// GET ALL FISCAL YEAR START AND END UNIX TIMES // GET ALL FISCAL YEAR START AND END UNIX TIMES
type TestCase_getAllFiscalYearsStartAndEndUnixTimes = { type TestCase_getAllFiscalYearsStartAndEndUnixTimes = {
startYearMonth: string; startYearMonth: TextualYearMonth;
endYearMonth: string; endYearMonth: TextualYearMonth;
fiscalYearStart: string; fiscalYearStart: string;
fiscalYearStartId: string; fiscalYearStartId: string;
expected: FiscalYearUnixTime[] expected: FiscalYearUnixTime[]
+163 -126
View File
@@ -2,11 +2,15 @@ import moment from 'moment-timezone';
import { type unitOfTime } from 'moment/moment'; import { type unitOfTime } from 'moment/moment';
import { import {
type DateTime,
type TextualYearMonth,
type TextualYearMonthDay,
type YearUnixTime, type YearUnixTime,
type YearQuarter, type YearQuarter,
type Year0BasedMonth, type Year0BasedMonth,
type Year1BasedMonth, type Year1BasedMonth,
type YearMonthRange, type YearMonthRange,
type YearMonthDay,
type TimeRange, type TimeRange,
type TimeRangeAndDateType, type TimeRangeAndDateType,
type TimeDifference, type TimeDifference,
@@ -35,7 +39,120 @@ import {
isNumber isNumber
} from './common.ts'; } from './common.ts';
type SupportedDate = Date | moment.Moment; class MomentDateTime implements DateTime {
private instance: moment.Moment;
private constructor(instance: moment.Moment) {
this.instance = instance;
}
public getUnixTime(): number {
return this.instance.unix();
}
public getLocalizedCalendarYear(): number {
return this.instance.year();
}
public getGregorianCalendarYear(): number {
return this.instance.year();
}
public getGregorianCalendarQuarter(): number {
return this.instance.quarter();
}
public getLocalizedCalendarQuarter(): number {
return this.instance.quarter();
}
public getGregorianCalendarMonth(): number {
return this.instance.month() + 1;
}
public getGregorianCalendarMonthName(): string {
return (Month.valueOf(this.instance.month() + 1) as Month).name;
}
public getLocalizedCalendarMonth(): number {
return this.instance.month() + 1;
}
public getGregorianCalendarDay(): number {
return this.instance.date();
}
public getLocalizedCalendarDay(): number {
return this.instance.date();
}
public getGregorianCalendarYearDashMonthDashDay(): TextualYearMonthDay {
return (this.instance.year() + '-' + (this.instance.month() + 1).toString().padStart(2, '0') + '-' + this.instance.date().toString().padStart(2, '0')) as TextualYearMonthDay;
}
public getGregorianCalendarYearDashMonth(): TextualYearMonth {
return (this.instance.year() + '-' + (this.instance.month() + 1).toString().padStart(2, '0')) as TextualYearMonth;
}
public getWeekDay(): WeekDay {
return WeekDay.valueOf(this.instance.days()) as WeekDay;
}
public toGregorianCalendarYearMonthDay(): YearMonthDay {
return {
year: this.instance.year(),
month: this.instance.month() + 1,
day: this.instance.date()
};
}
public toGregorianCalendarYear0BasedMonth(): Year0BasedMonth {
return {
year: this.instance.year(),
month0base: this.instance.month()
};
}
public format(format: string): string {
return this.instance.format(format);
}
public static of(instance: moment.Moment): DateTime {
return new MomentDateTime(instance);
}
public static now(): DateTime {
return new MomentDateTime(moment());
}
static isYearFirstTime(dateTime: MomentDateTime): boolean {
const currentUnixTime = dateTime.instance.clone().set({ millisecond: 0 }).unix();
const expectedUnxTime = dateTime.instance.clone().set({ millisecond: 0 }).startOf('year').unix();
return currentUnixTime === expectedUnxTime;
}
static isYearLastTime(dateTime: MomentDateTime): boolean {
const currentUnixTime = dateTime.instance.clone().set({ millisecond: 999 }).unix();
const expectedUnxTime = dateTime.instance.clone().set({ millisecond: 999 }).endOf('year').unix();
return currentUnixTime === expectedUnxTime;
}
static isMonthFirstTime(dateTime: MomentDateTime): boolean {
const currentUnixTime = dateTime.instance.clone().set({ millisecond: 0 }).unix();
const expectedUnxTime = dateTime.instance.clone().set({ millisecond: 0 }).startOf('month').unix();
return currentUnixTime === expectedUnxTime;
}
static isMonthLastTime(dateTime: MomentDateTime): boolean {
const currentUnixTime = dateTime.instance.clone().set({ millisecond: 999 }).unix();
const expectedUnxTime = dateTime.instance.clone().set({ millisecond: 999 }).endOf('month').unix();
return currentUnixTime === expectedUnxTime;
}
}
export function getAllowedYearRange(): number[] {
return [2000, moment().year() + 1];
}
export function isYear0BasedMonthValid(year: number, month0base: number): boolean { export function isYear0BasedMonthValid(year: number, month0base: number): boolean {
if (!isNumber(year) || !isNumber(month0base)) { if (!isNumber(year) || !isNumber(month0base)) {
@@ -54,7 +171,7 @@ export function getYear0BasedMonthObjectFromUnixTime(unixTime: number): Year0Bas
}; };
} }
export function getYear0BasedMonthObjectFromString(yearMonth: string): Year0BasedMonth | null { export function getYear0BasedMonthObjectFromString(yearMonth: TextualYearMonth | ''): Year0BasedMonth | null {
if (!isString(yearMonth)) { if (!isString(yearMonth)) {
return null; return null;
} }
@@ -78,12 +195,12 @@ export function getYear0BasedMonthObjectFromString(yearMonth: string): Year0Base
}; };
} }
export function getYearMonthStringFromYear0BasedMonthObject(yearMonth: Year0BasedMonth | null): string { export function getYearMonthStringFromYear0BasedMonthObject(yearMonth: Year0BasedMonth | null): TextualYearMonth | '' {
if (!yearMonth || !isYear0BasedMonthValid(yearMonth.year, yearMonth.month0base)) { if (!yearMonth || !isYear0BasedMonthValid(yearMonth.year, yearMonth.month0base)) {
return ''; return '';
} }
return `${yearMonth.year}-${yearMonth.month0base + 1}`; return (`${yearMonth.year}-${yearMonth.month0base + 1}`) as TextualYearMonth;
} }
export function getHourIn12HourFormat(hour: number): number { export function getHourIn12HourFormat(hour: number): number {
@@ -122,16 +239,8 @@ export function getUtcOffsetByUtcOffsetMinutes(utcOffsetMinutes: number): string
const offsetHours = Math.trunc(Math.abs(utcOffsetMinutes) / 60); const offsetHours = Math.trunc(Math.abs(utcOffsetMinutes) / 60);
const offsetMinutes = Math.abs(utcOffsetMinutes) - offsetHours * 60; const offsetMinutes = Math.abs(utcOffsetMinutes) - offsetHours * 60;
let finalOffsetHours = offsetHours.toString(); const finalOffsetHours = offsetHours.toString().padStart(2, '0');
let finalOffsetMinutes = offsetMinutes.toString(); const finalOffsetMinutes = offsetMinutes.toString().padStart(2, '0');
if (offsetHours < 10) {
finalOffsetHours = '0' + offsetHours;
}
if (offsetMinutes < 10) {
finalOffsetMinutes = '0' + offsetMinutes;
}
if (utcOffsetMinutes >= 0) { if (utcOffsetMinutes >= 0) {
return `+${finalOffsetHours}:${finalOffsetMinutes}`; return `+${finalOffsetHours}:${finalOffsetMinutes}`;
@@ -180,23 +289,15 @@ export function getDummyUnixTimeForLocalUsage(unixTime: number, utcOffset: numbe
return unixTime + (utcOffset - currentUtcOffset) * 60; return unixTime + (utcOffset - currentUtcOffset) * 60;
} }
export function getCurrentDateTime(): DateTime {
return MomentDateTime.now();
}
export function getCurrentUnixTime(): number { export function getCurrentUnixTime(): number {
return moment().unix(); return moment().unix();
} }
export function getCurrentYear(): number { export function parseDateTimeFromUnixTime(unixTime: number, utcOffset?: number, currentUtcOffset?: number): DateTime {
return moment().year();
}
export function getCurrentYearAndMonth(): string {
return getYearAndMonth(moment());
}
export function getCurrentDay(): number {
return moment().date();
}
export function parseDateFromUnixTime(unixTime: number, utcOffset?: number, currentUtcOffset?: number): moment.Moment {
if (isNumber(utcOffset)) { if (isNumber(utcOffset)) {
if (!isNumber(currentUtcOffset)) { if (!isNumber(currentUtcOffset)) {
currentUtcOffset = getTimezoneOffsetMinutes(); currentUtcOffset = getTimezoneOffsetMinutes();
@@ -205,73 +306,31 @@ export function parseDateFromUnixTime(unixTime: number, utcOffset?: number, curr
unixTime = getDummyUnixTimeForLocalUsage(unixTime, utcOffset, currentUtcOffset); unixTime = getDummyUnixTimeForLocalUsage(unixTime, utcOffset, currentUtcOffset);
} }
return moment.unix(unixTime); return MomentDateTime.of(moment.unix(unixTime));
} }
export function formatUnixTime(unixTime: number, format: string, utcOffset?: number, currentUtcOffset?: number) { export function formatUnixTime(unixTime: number, format: string, utcOffset?: number, currentUtcOffset?: number): string {
return parseDateFromUnixTime(unixTime, utcOffset, currentUtcOffset).format(format); return parseDateTimeFromUnixTime(unixTime, utcOffset, currentUtcOffset).format(format);
} }
export function formatCurrentTime(format: string): string { export function formatCurrentTime(format: string): string {
return moment().format(format); return moment().format(format);
} }
export function formatDate(date: string, format: string): string { export function formatGregorianCalendarYearDashMonthDashDay(date: TextualYearMonthDay, format: string): string {
return moment(date, 'YYYY-MM-DD').format(format); return moment(date, 'YYYY-MM-DD').format(format);
} }
export function formatMonthDay(monthDay: string, format: string): string { export function formatGregorianCalendarMonthDashDay(monthDay: TextualYearMonth, format: string): string {
return moment(monthDay, 'MM-DD').format(format); return moment(monthDay, 'MM-DD').format(format);
} }
export function getUnixTime(date: SupportedDate): number { export function getGregorianCalendarYearAndMonthFromUnixTime(unixTime: number): TextualYearMonth | '' {
return moment(date).unix();
}
export function getShortDate(date: SupportedDate): string {
date = moment(date);
return date.year() + '-' + (date.month() + 1) + '-' + date.date();
}
export function getYear(date: SupportedDate): number {
return moment(date).year();
}
export function getQuarter(date: SupportedDate): number {
return moment(date).quarter();
}
export function getMonth(date: SupportedDate): number {
return moment(date).month() + 1;
}
export function getYearAndMonth(date: SupportedDate): string {
const year = getYear(date);
const month = getMonth(date);
return `${year}-${month}`;
}
export function getYearAndMonthFromUnixTime(unixTime: number): string {
if (!unixTime) { if (!unixTime) {
return ''; return '';
} }
return getYearAndMonth(parseDateFromUnixTime(unixTime)); return parseDateTimeFromUnixTime(unixTime).getGregorianCalendarYearDashMonth();
}
export function getDay(date: SupportedDate): number {
return moment(date).date();
}
export function getDayOfWeekName(date: SupportedDate): string {
const dayOfWeek = moment(date).days();
return (WeekDay.valueOf(dayOfWeek) as WeekDay).name;
}
export function getMonthName(date: SupportedDate): string {
const month = moment(date).month();
return (Month.valueOf(month + 1) as Month).name;
} }
export function getAMOrPM(hour: number): string { export function getAMOrPM(hour: number): string {
@@ -296,15 +355,6 @@ export function getTimeDifferenceHoursAndMinutes(timeDifferenceInMinutes: number
}; };
} }
export function getMinuteFirstUnixTime(date: SupportedDate): number {
const datetime = moment(date);
return datetime.set({ second: 0, millisecond: 0 }).unix();
}
export function getMinuteLastUnixTime(date: SupportedDate): number {
return moment.unix(getMinuteFirstUnixTime(date)).add(1, 'minutes').subtract(1, 'seconds').unix();
}
export function getTodayFirstUnixTime(): number { export function getTodayFirstUnixTime(): number {
return moment().set({ hour: 0, minute: 0, second: 0, millisecond: 0 }).unix(); return moment().set({ hour: 0, minute: 0, second: 0, millisecond: 0 }).unix();
} }
@@ -412,7 +462,7 @@ export function getQuarterLastUnixTime(yearQuarter: YearQuarter): number {
return moment.unix(getQuarterFirstUnixTime(yearQuarter)).add(3, 'months').subtract(1, 'seconds').unix(); return moment.unix(getQuarterFirstUnixTime(yearQuarter)).add(3, 'months').subtract(1, 'seconds').unix();
} }
export function getYearMonthFirstUnixTime(yearMonth: Year0BasedMonth | Year1BasedMonth | string): number { export function getYearMonthFirstUnixTime(yearMonth: Year0BasedMonth | Year1BasedMonth | TextualYearMonth | ''): number {
let yearMonthObj: Year0BasedMonth | null = null; let yearMonthObj: Year0BasedMonth | null = null;
if (isString(yearMonth)) { if (isString(yearMonth)) {
@@ -433,11 +483,11 @@ export function getYearMonthFirstUnixTime(yearMonth: Year0BasedMonth | Year1Base
return moment().set({ year: yearMonthObj.year, month: yearMonthObj.month0base, date: 1, hour: 0, minute: 0, second: 0, millisecond: 0 }).unix(); return moment().set({ year: yearMonthObj.year, month: yearMonthObj.month0base, date: 1, hour: 0, minute: 0, second: 0, millisecond: 0 }).unix();
} }
export function getYearMonthLastUnixTime(yearMonth: Year0BasedMonth | Year1BasedMonth | string): number { export function getYearMonthLastUnixTime(yearMonth: Year0BasedMonth | Year1BasedMonth | TextualYearMonth | ''): number {
return moment.unix(getYearMonthFirstUnixTime(yearMonth)).add(1, 'months').subtract(1, 'seconds').unix(); return moment.unix(getYearMonthFirstUnixTime(yearMonth)).add(1, 'months').subtract(1, 'seconds').unix();
} }
export function getStartEndYearMonthRange(startYearMonth: Year0BasedMonth | Year1BasedMonth | string, endYearMonth: Year0BasedMonth | Year1BasedMonth | string): YearMonthRange | null { export function getStartEndYearMonthRange(startYearMonth: Year0BasedMonth | Year1BasedMonth | TextualYearMonth | '', endYearMonth: Year0BasedMonth | Year1BasedMonth | TextualYearMonth | ''): YearMonthRange | null {
let startYearMonthObj: Year0BasedMonth | null = null; let startYearMonthObj: Year0BasedMonth | null = null;
let endYearMonthObj: Year0BasedMonth | null = null; let endYearMonthObj: Year0BasedMonth | null = null;
@@ -473,7 +523,7 @@ export function getStartEndYearMonthRange(startYearMonth: Year0BasedMonth | Year
}; };
} }
export function getAllYearsStartAndEndUnixTimes(startYearMonth: Year0BasedMonth | Year1BasedMonth | string, endYearMonth: Year0BasedMonth | Year1BasedMonth | string): YearUnixTime[] { export function getAllYearsStartAndEndUnixTimes(startYearMonth: Year0BasedMonth | Year1BasedMonth | TextualYearMonth | '', endYearMonth: Year0BasedMonth | Year1BasedMonth | TextualYearMonth | ''): YearUnixTime[] {
const allYearTimes: YearUnixTime[] = []; const allYearTimes: YearUnixTime[] = [];
const range = getStartEndYearMonthRange(startYearMonth, endYearMonth); const range = getStartEndYearMonthRange(startYearMonth, endYearMonth);
@@ -494,7 +544,7 @@ export function getAllYearsStartAndEndUnixTimes(startYearMonth: Year0BasedMonth
return allYearTimes; return allYearTimes;
} }
export function getAllFiscalYearsStartAndEndUnixTimes(startYearMonth: Year0BasedMonth | Year1BasedMonth | string, endYearMonth: Year0BasedMonth | Year1BasedMonth | string, fiscalYearStartValue: number): FiscalYearUnixTime[] { export function getAllFiscalYearsStartAndEndUnixTimes(startYearMonth: Year0BasedMonth | Year1BasedMonth | TextualYearMonth | '', endYearMonth: Year0BasedMonth | Year1BasedMonth | TextualYearMonth | '', fiscalYearStartValue: number): FiscalYearUnixTime[] {
// user selects date range: start=2024-01 and end=2026-12 // user selects date range: start=2024-01 and end=2026-12
// result should be 4x FiscalYearUnixTime made up of: // result should be 4x FiscalYearUnixTime made up of:
// - 2024-01->2024-06 (FY 24) - input start year-month->end of fiscal year in which the input start year-month falls // - 2024-01->2024-06 (FY 24) - input start year-month->end of fiscal year in which the input start year-month falls
@@ -544,7 +594,7 @@ export function getAllFiscalYearsStartAndEndUnixTimes(startYearMonth: Year0Based
return allFiscalYearTimes; return allFiscalYearTimes;
} }
export function getAllQuartersStartAndEndUnixTimes(startYearMonth: Year0BasedMonth | Year1BasedMonth | string, endYearMonth: Year0BasedMonth | Year1BasedMonth | string): YearQuarterUnixTime[] { export function getAllQuartersStartAndEndUnixTimes(startYearMonth: Year0BasedMonth | Year1BasedMonth | TextualYearMonth | '', endYearMonth: Year0BasedMonth | Year1BasedMonth | TextualYearMonth | ''): YearQuarterUnixTime[] {
const allYearQuarterTimes: YearQuarterUnixTime[] = []; const allYearQuarterTimes: YearQuarterUnixTime[] = [];
const range = getStartEndYearMonthRange(startYearMonth, endYearMonth); const range = getStartEndYearMonthRange(startYearMonth, endYearMonth);
@@ -578,7 +628,7 @@ export function getAllQuartersStartAndEndUnixTimes(startYearMonth: Year0BasedMon
return allYearQuarterTimes; return allYearQuarterTimes;
} }
export function getAllMonthsStartAndEndUnixTimes(startYearMonth: Year0BasedMonth | Year1BasedMonth | string, endYearMonth: Year0BasedMonth | Year1BasedMonth | string): YearMonthUnixTime[] { export function getAllMonthsStartAndEndUnixTimes(startYearMonth: Year0BasedMonth | Year1BasedMonth | TextualYearMonth | '', endYearMonth: Year0BasedMonth | Year1BasedMonth | TextualYearMonth | ''): YearMonthUnixTime[] {
const allYearMonthTimes: YearMonthUnixTime[] = []; const allYearMonthTimes: YearMonthUnixTime[] = [];
const range = getStartEndYearMonthRange(startYearMonth, endYearMonth); const range = getStartEndYearMonthRange(startYearMonth, endYearMonth);
@@ -622,16 +672,11 @@ export function getAllDaysStartAndEndUnixTimes(startUnixTime: number, endUnixTim
let unixTime: number = startUnixTime; let unixTime: number = startUnixTime;
while (unixTime <= endUnixTime) { while (unixTime <= endUnixTime) {
const currentDay = parseDateFromUnixTime(unixTime); const currentDateTime = parseDateTimeFromUnixTime(unixTime);
const currentDayMinUnixTime = getDayFirstUnixTimeBySpecifiedUnixTime(unixTime); const currentDayMinUnixTime = getDayFirstUnixTimeBySpecifiedUnixTime(unixTime);
const currentDayMaxUnixTime = getDayLastUnixTimeBySpecifiedUnixTime(unixTime); const currentDayMaxUnixTime = getDayLastUnixTimeBySpecifiedUnixTime(unixTime);
allYearMonthDayTimes.push(YearMonthDayUnixTime.of({ allYearMonthDayTimes.push(YearMonthDayUnixTime.of(currentDateTime.toGregorianCalendarYearMonthDay(), currentDayMinUnixTime, currentDayMaxUnixTime));
year: currentDay.year(),
month: currentDay.month() + 1,
day: currentDay.date()
}, currentDayMinUnixTime, currentDayMaxUnixTime));
unixTime = currentDayMaxUnixTime + 1; unixTime = currentDayMaxUnixTime + 1;
} }
@@ -649,15 +694,15 @@ export function getDateTimeFormatType<T extends DateFormat | TimeFormat>(allForm
} }
export function getShiftedDateRange(minTime: number, maxTime: number, scale: number): TimeRange { export function getShiftedDateRange(minTime: number, maxTime: number, scale: number): TimeRange {
const minDateTime = parseDateFromUnixTime(minTime).set({ millisecond: 0 }); const minDateTime = moment.unix(parseDateTimeFromUnixTime(minTime).getUnixTime()).set({ millisecond: 0 });
const maxDateTime = parseDateFromUnixTime(maxTime).set({ millisecond: 999 }); const maxDateTime = moment.unix(parseDateTimeFromUnixTime(maxTime).getUnixTime()).set({ millisecond: 999 });
const firstDayOfMonth = minDateTime.clone().startOf('month'); const firstDayOfMonth = minDateTime.clone().startOf('month');
const lastDayOfMonth = maxDateTime.clone().endOf('month'); const lastDayOfMonth = maxDateTime.clone().endOf('month');
// check whether the date range matches full months // check whether the date range matches full months
if (firstDayOfMonth.unix() === minDateTime.unix() && lastDayOfMonth.unix() === maxDateTime.unix()) { if (firstDayOfMonth.unix() === minDateTime.unix() && lastDayOfMonth.unix() === maxDateTime.unix()) {
const months = getYear(maxDateTime) * 12 + getMonth(maxDateTime) - getYear(minDateTime) * 12 - getMonth(minDateTime) + 1; const months = maxDateTime.year() * 12 + (maxDateTime.month() + 1) - minDateTime.year() * 12 - (minDateTime.month() + 1) + 1;
const newMinDateTime = minDateTime.add(months * scale, 'months'); const newMinDateTime = minDateTime.add(months * scale, 'months');
const newMaxDateTime = newMinDateTime.clone().add(months, 'months').subtract(1, 'seconds'); const newMaxDateTime = newMinDateTime.clone().add(months, 'months').subtract(1, 'seconds');
@@ -848,7 +893,7 @@ export function getDateRangeByBillingCycleDateType(dateType: number, firstDayOfW
if (dateType === DateRange.PreviousBillingCycle.type || dateType === DateRange.CurrentBillingCycle.type) { // Previous Billing Cycle | Current Billing Cycle if (dateType === DateRange.PreviousBillingCycle.type || dateType === DateRange.CurrentBillingCycle.type) { // Previous Billing Cycle | Current Billing Cycle
if (statementDate) { if (statementDate) {
if (getCurrentDay() <= statementDate) { if (getCurrentDateTime().getGregorianCalendarDay() <= statementDate) {
maxTime = getThisMonthSpecifiedDayLastUnixTime(statementDate); maxTime = getThisMonthSpecifiedDayLastUnixTime(statementDate);
minTime = getUnixTimeBeforeUnixTime(getUnixTimeAfterUnixTime(getThisMonthSpecifiedDayFirstUnixTime(statementDate), 1, 'days'), 1, 'months'); minTime = getUnixTimeBeforeUnixTime(getUnixTimeAfterUnixTime(getThisMonthSpecifiedDayFirstUnixTime(statementDate), 1, 'days'), 1, 'months');
} else { } else {
@@ -898,8 +943,8 @@ export function getRecentMonthDateRanges(monthCount: number): RecentMonthDateRan
const maxTime = getUnixTimeBeforeUnixTime(getUnixTimeAfterUnixTime(minTime, 1, 'months'), 1, 'seconds'); const maxTime = getUnixTimeBeforeUnixTime(getUnixTimeAfterUnixTime(minTime, 1, 'months'), 1, 'seconds');
let dateType = DateRange.Custom.type; let dateType = DateRange.Custom.type;
const year = getYear(parseDateFromUnixTime(minTime)); const year = parseDateTimeFromUnixTime(minTime).getGregorianCalendarYear();
const month = getMonth(parseDateFromUnixTime(minTime)); const month = parseDateTimeFromUnixTime(minTime).getGregorianCalendarMonth();
if (i === 0) { if (i === 0) {
dateType = DateRange.ThisMonth.type; dateType = DateRange.ThisMonth.type;
@@ -1004,7 +1049,7 @@ export function getCombinedDateAndTimeValues(date: Date, hour: string, minute: s
return newDateTime; return newDateTime;
} }
export function getValidMonthDayOrCurrentDayShortDate(unixTime: number, currentShortDate: string): string { export function getValidMonthDayOrCurrentDayShortDate(unixTime: number, currentShortDate: string): TextualYearMonthDay {
const currentTime = moment(); const currentTime = moment();
const monthLastTime = moment.unix(getMonthLastUnixTimeBySpecifiedUnixTime(unixTime)); const monthLastTime = moment.unix(getMonthLastUnixTimeBySpecifiedUnixTime(unixTime));
@@ -1015,43 +1060,35 @@ export function getValidMonthDayOrCurrentDayShortDate(unixTime: number, currentS
const currentDay = parseInt(yearMonthDay[2]); const currentDay = parseInt(yearMonthDay[2]);
if (currentDay < monthLastTime.date()) { if (currentDay < monthLastTime.date()) {
return getShortDate(monthLastTime.set({ date: currentDay })); return MomentDateTime.of(monthLastTime.set({ date: currentDay })).getGregorianCalendarYearDashMonthDashDay();
} }
} }
} }
if (monthLastTime.year() === currentTime.year() && monthLastTime.month() === currentTime.month()) { if (monthLastTime.year() === currentTime.year() && monthLastTime.month() === currentTime.month()) {
return getShortDate(currentTime); return MomentDateTime.of(currentTime).getGregorianCalendarYearDashMonthDashDay();
} }
return getShortDate(monthLastTime); return MomentDateTime.of(monthLastTime).getGregorianCalendarYearDashMonthDashDay();
} }
export function isDateRangeMatchFullYears(minTime: number, maxTime: number): boolean { export function isDateRangeMatchFullYears(minTime: number, maxTime: number): boolean {
const minDateTime = parseDateFromUnixTime(minTime).set({ millisecond: 0 }); const minDateTime = parseDateTimeFromUnixTime(minTime);
const maxDateTime = parseDateFromUnixTime(maxTime).set({ millisecond: 999 }); const maxDateTime = parseDateTimeFromUnixTime(maxTime);
return MomentDateTime.isYearFirstTime(minDateTime as MomentDateTime) && MomentDateTime.isYearLastTime(maxDateTime as MomentDateTime);
const firstDayOfYear = minDateTime.clone().startOf('year');
const lastDayOfYear = maxDateTime.clone().endOf('year');
return firstDayOfYear.unix() === minDateTime.unix() && lastDayOfYear.unix() === maxDateTime.unix();
} }
export function isDateRangeMatchFullMonths(minTime: number, maxTime: number): boolean { export function isDateRangeMatchFullMonths(minTime: number, maxTime: number): boolean {
const minDateTime = parseDateFromUnixTime(minTime).set({ millisecond: 0 }); const minDateTime = parseDateTimeFromUnixTime(minTime);
const maxDateTime = parseDateFromUnixTime(maxTime).set({ millisecond: 999 }); const maxDateTime = parseDateTimeFromUnixTime(maxTime);
return MomentDateTime.isMonthFirstTime(minDateTime as MomentDateTime) && MomentDateTime.isMonthLastTime(maxDateTime as MomentDateTime);
const firstDayOfMonth = minDateTime.clone().startOf('month');
const lastDayOfMonth = maxDateTime.clone().endOf('month');
return firstDayOfMonth.unix() === minDateTime.unix() && lastDayOfMonth.unix() === maxDateTime.unix();
} }
export function isDateRangeMatchOneMonth(minTime: number, maxTime: number): boolean { export function isDateRangeMatchOneMonth(minTime: number, maxTime: number): boolean {
const minDateTime = parseDateFromUnixTime(minTime); const minDateTime = parseDateTimeFromUnixTime(minTime);
const maxDateTime = parseDateFromUnixTime(maxTime); const maxDateTime = parseDateTimeFromUnixTime(maxTime);
if (getYear(minDateTime) !== getYear(maxDateTime) || getMonth(minDateTime) !== getMonth(maxDateTime)) { if (minDateTime.getGregorianCalendarYear() !== maxDateTime.getGregorianCalendarYear() || minDateTime.getGregorianCalendarMonth() !== maxDateTime.getGregorianCalendarMonth()) {
return false; return false;
} }
+5 -5
View File
@@ -1,4 +1,4 @@
import type { Year1BasedMonth, YearUnixTime, YearQuarterUnixTime, YearMonthUnixTime } from '@/core/datetime.ts'; import type { TextualYearMonth, Year1BasedMonth, YearUnixTime, YearQuarterUnixTime, YearMonthUnixTime } from '@/core/datetime.ts';
import type { FiscalYearUnixTime } from '@/core/fiscalyear.ts'; import type { FiscalYearUnixTime } from '@/core/fiscalyear.ts';
import { ChartSortingType, ChartDateAggregationType } from '@/core/statistics.ts'; import { ChartSortingType, ChartDateAggregationType } from '@/core/statistics.ts';
import type { import type {
@@ -48,7 +48,7 @@ export function sortStatisticsItems<T extends SortableTransactionStatisticDataIt
} }
} }
export function getAllDateRangesFromItems<T extends Year1BasedMonth>(items: YearMonthItems<T>[], startYearMonth: Year1BasedMonth | string, endYearMonth: Year1BasedMonth | string, fiscalYearStart: number, dateAggregationType: number): YearUnixTime[] | FiscalYearUnixTime[] | YearQuarterUnixTime[] | YearMonthUnixTime[] { export function getAllDateRangesFromItems<T extends Year1BasedMonth>(items: YearMonthItems<T>[], startYearMonth: Year1BasedMonth | TextualYearMonth | '', endYearMonth: Year1BasedMonth | TextualYearMonth | '', fiscalYearStart: number, dateAggregationType: number): YearUnixTime[] | FiscalYearUnixTime[] | YearQuarterUnixTime[] | YearMonthUnixTime[] {
if ((!startYearMonth || !endYearMonth) && items && items.length) { if ((!startYearMonth || !endYearMonth) && items && items.length) {
let minYear = Number.MAX_SAFE_INTEGER, minMonth = Number.MAX_SAFE_INTEGER, maxYear = 0, maxMonth = 0; let minYear = Number.MAX_SAFE_INTEGER, minMonth = Number.MAX_SAFE_INTEGER, maxYear = 0, maxMonth = 0;
@@ -70,14 +70,14 @@ export function getAllDateRangesFromItems<T extends Year1BasedMonth>(items: Year
} }
} }
startYearMonth = `${minYear}-${minMonth}`; startYearMonth = `${minYear}-${minMonth}` as TextualYearMonth;
endYearMonth = `${maxYear}-${maxMonth}`; endYearMonth = `${maxYear}-${maxMonth}` as TextualYearMonth;
} }
return getAllDateRangesByYearMonthRange(startYearMonth, endYearMonth, fiscalYearStart, dateAggregationType); return getAllDateRangesByYearMonthRange(startYearMonth, endYearMonth, fiscalYearStart, dateAggregationType);
} }
export function getAllDateRangesByYearMonthRange(startYearMonth: Year1BasedMonth | string, endYearMonth: Year1BasedMonth | string, fiscalYearStart: number, dateAggregationType: number): YearUnixTime[] | FiscalYearUnixTime[] | YearQuarterUnixTime[] | YearMonthUnixTime[] { export function getAllDateRangesByYearMonthRange(startYearMonth: Year1BasedMonth | TextualYearMonth | '', endYearMonth: Year1BasedMonth | TextualYearMonth | '', fiscalYearStart: number, dateAggregationType: number): YearUnixTime[] | FiscalYearUnixTime[] | YearQuarterUnixTime[] | YearMonthUnixTime[] {
if (!startYearMonth || !endYearMonth) { if (!startYearMonth || !endYearMonth) {
return []; return [];
} }
+22 -22
View File
@@ -16,6 +16,8 @@ import {
} from '@/core/text.ts'; } from '@/core/text.ts';
import { import {
type TextualYearMonth,
type TextualYearMonthDay,
type DateFormat, type DateFormat,
type TimeFormat, type TimeFormat,
type LocalizedDateTimeFormat, type LocalizedDateTimeFormat,
@@ -148,12 +150,13 @@ import {
import { import {
formatCurrentTime, formatCurrentTime,
formatDate, formatGregorianCalendarYearDashMonthDashDay,
formatMonthDay, formatGregorianCalendarMonthDashDay,
formatUnixTime, formatUnixTime,
getBrowserTimezoneOffset, getBrowserTimezoneOffset,
getBrowserTimezoneOffsetMinutes, getBrowserTimezoneOffsetMinutes,
getCurrentUnixTime, getCurrentUnixTime,
parseDateTimeFromUnixTime,
getDateTimeFormatType, getDateTimeFormatType,
getFiscalYearTimeRangeFromUnixTime, getFiscalYearTimeRangeFromUnixTime,
getFiscalYearTimeRangeFromYear, getFiscalYearTimeRangeFromYear,
@@ -161,12 +164,9 @@ import {
getTimeDifferenceHoursAndMinutes, getTimeDifferenceHoursAndMinutes,
getTimezoneOffset, getTimezoneOffset,
getTimezoneOffsetMinutes, getTimezoneOffsetMinutes,
getYear,
getQuarter,
isDateRangeMatchFullMonths, isDateRangeMatchFullMonths,
isDateRangeMatchFullYears, isDateRangeMatchFullYears,
isPM, isPM
parseDateFromUnixTime,
} from '@/lib/datetime.ts'; } from '@/lib/datetime.ts';
import { import {
@@ -1441,12 +1441,12 @@ export function useI18n() {
}); });
} }
function getWeekdayShortName(weekDayName: string): string { function getWeekdayShortName(weekDay: WeekDay): string {
return t(`datetime.${weekDayName}.short`); return t(`datetime.${weekDay.name}.short`);
} }
function getWeekdayLongName(weekDayName: string): string { function getWeekdayLongName(weekDay: WeekDay): string {
return t(`datetime.${weekDayName}.long`); return t(`datetime.${weekDay.name}.long`);
} }
function getMultiMonthdayShortNames(monthDays: number[]): string { function getMultiMonthdayShortNames(monthDays: number[]): string {
@@ -1618,18 +1618,18 @@ export function useI18n() {
return getLocalizedLongTimeFormat().indexOf('ss') >= 0; return getLocalizedLongTimeFormat().indexOf('ss') >= 0;
} }
function formatDateToLongDate(date: string): string { function formatGregorianCalendarYearDashMonthDashDayToLongDate(date: TextualYearMonthDay): string {
return formatDate(date, getLocalizedLongDateFormat()); return formatGregorianCalendarYearDashMonthDashDay(date, getLocalizedLongDateFormat());
} }
function formatMonthDayToLongDay(monthDay: string): string { function formatGregorianCalendarMonthDashDayToLongMonthDay(monthDay: TextualYearMonth): string {
return formatMonthDay(monthDay, getLocalizedLongMonthDayFormat()); return formatGregorianCalendarMonthDashDay(monthDay, getLocalizedLongMonthDayFormat());
} }
function formatUnixTimeToYearQuarter(unixTime: number): string { function formatUnixTimeToYearQuarter(unixTime: number): string {
const date = parseDateFromUnixTime(unixTime); const date = parseDateTimeFromUnixTime(unixTime);
const year = getYear(date); const year = date.getLocalizedCalendarYear();
const quarter = getQuarter(date); const quarter = date.getLocalizedCalendarQuarter();
return formatYearQuarter(year, quarter); return formatYearQuarter(year, quarter);
} }
@@ -1675,8 +1675,8 @@ export function useI18n() {
return displayStartTime !== displayEndTime ? `${displayStartTime} ~ ${displayEndTime}` : displayStartTime; return displayStartTime !== displayEndTime ? `${displayStartTime} ~ ${displayEndTime}` : displayStartTime;
} }
const startTimeYear = getYear(parseDateFromUnixTime(startTime)); const startTimeYear = parseDateTimeFromUnixTime(startTime).getLocalizedCalendarYear();
const endTimeYear = getYear(parseDateFromUnixTime(endTime)); const endTimeYear = parseDateTimeFromUnixTime(endTime).getLocalizedCalendarYear();
const format = getLocalizedShortDateFormat(); const format = getLocalizedShortDateFormat();
const displayStartTime = formatUnixTime(startTime, format); const displayStartTime = formatUnixTime(startTime, format);
@@ -1734,7 +1734,7 @@ export function useI18n() {
fiscalYearStart = FiscalYearStart.Default; fiscalYearStart = FiscalYearStart.Default;
} }
return formatMonthDayToLongDay(fiscalYearStart.toMonthDashDayString()); return formatGregorianCalendarMonthDashDayToLongMonthDay(fiscalYearStart.toMonthDashDayString());
} }
function getTimezoneDifferenceDisplayText(utcOffset: number): string { function getTimezoneDifferenceDisplayText(utcOffset: number): string {
@@ -2168,8 +2168,8 @@ export function useI18n() {
formatUnixTimeToShortMonthDay: (unixTime: number, utcOffset?: number, currentUtcOffset?: number) => formatUnixTime(unixTime, getLocalizedShortMonthDayFormat(), utcOffset, currentUtcOffset), formatUnixTimeToShortMonthDay: (unixTime: number, utcOffset?: number, currentUtcOffset?: number) => formatUnixTime(unixTime, getLocalizedShortMonthDayFormat(), utcOffset, currentUtcOffset),
formatUnixTimeToLongTime: (unixTime: number, utcOffset?: number, currentUtcOffset?: number) => formatUnixTime(unixTime, getLocalizedLongTimeFormat(), utcOffset, currentUtcOffset), formatUnixTimeToLongTime: (unixTime: number, utcOffset?: number, currentUtcOffset?: number) => formatUnixTime(unixTime, getLocalizedLongTimeFormat(), utcOffset, currentUtcOffset),
formatUnixTimeToShortTime: (unixTime: number, utcOffset?: number, currentUtcOffset?: number) => formatUnixTime(unixTime, getLocalizedShortTimeFormat(), utcOffset, currentUtcOffset), formatUnixTimeToShortTime: (unixTime: number, utcOffset?: number, currentUtcOffset?: number) => formatUnixTime(unixTime, getLocalizedShortTimeFormat(), utcOffset, currentUtcOffset),
formatDateToLongDate, formatGregorianCalendarYearDashMonthDashDayToLongDate,
formatMonthDayToLongDay, formatGregorianCalendarMonthDashDayToLongMonthDay,
formatUnixTimeToYearQuarter, formatUnixTimeToYearQuarter,
formatYearQuarter, formatYearQuarter,
formatDateRange, formatDateRange,
+14 -14
View File
@@ -1,5 +1,5 @@
import type { PartialRecord } from '@/core/base.ts'; import type { PartialRecord } from '@/core/base.ts';
import type { Year1BasedMonth, StartEndTime } from '@/core/datetime.ts'; import type { Year1BasedMonth, TextualYearMonthDay, StartEndTime, WeekDay } from '@/core/datetime.ts';
import { type Coordinate, getNormalizedCoordinate } from '@/core/coordinate.ts'; import { type Coordinate, getNormalizedCoordinate } from '@/core/coordinate.ts';
import { TransactionType } from '@/core/transaction.ts'; import { TransactionType } from '@/core/transaction.ts';
@@ -35,9 +35,9 @@ export class Transaction implements TransactionInfoResponse {
private _destinationAccount?: Account; // only for displaying transaction private _destinationAccount?: Account; // only for displaying transaction
private _tags?: TransactionTag[]; // only for displaying transaction private _tags?: TransactionTag[]; // only for displaying transaction
private _date?: string = undefined; // only for displaying transaction in transaction list private _gregorianCalendarYearDashMonthDashDay?: TextualYearMonthDay = undefined; // only for displaying transaction in transaction list
private _day?: number = undefined; // only for displaying transaction in transaction list private _gregorianCalendarDayOfMonth?: number = undefined; // only for displaying transaction in transaction list
private _dayOfWeek?: string = undefined; // only for displaying transaction in transaction list private _displayDayOfWeek?: WeekDay = undefined; // only for displaying transaction in transaction list
protected constructor(id: string, timeSequenceId: string, type: number, categoryId: string, time: number, timeZone: string | undefined, utcOffset: number, sourceAccountId: string, destinationAccountId: string, sourceAmount: number, destinationAmount: number, hideAmount: boolean, tagIds: string[], comment: string, editable: boolean) { protected constructor(id: string, timeSequenceId: string, type: number, categoryId: string, time: number, timeZone: string | undefined, utcOffset: number, sourceAccountId: string, destinationAccountId: string, sourceAmount: number, destinationAmount: number, hideAmount: boolean, tagIds: string[], comment: string, editable: boolean) {
this.id = id; this.id = id;
@@ -106,16 +106,16 @@ export class Transaction implements TransactionInfoResponse {
return ret; return ret;
} }
public get date(): string | undefined { public get gregorianCalendarYearDashMonthDashDay(): TextualYearMonthDay | undefined {
return this._date; return this._gregorianCalendarYearDashMonthDashDay;
} }
public get day(): number | undefined { public get gregorianCalendarDayOfMonth(): number | undefined {
return this._day; return this._gregorianCalendarDayOfMonth;
} }
public get dayOfWeek(): string | undefined { public get displayDayOfWeek(): WeekDay | undefined {
return this._dayOfWeek; return this._displayDayOfWeek;
} }
public getCategoryId(): string { public getCategoryId(): string {
@@ -220,10 +220,10 @@ export class Transaction implements TransactionInfoResponse {
this._geoLocation = undefined; this._geoLocation = undefined;
} }
public setDisplayDate(date: string, day: number, dayOfWeek: string): void { public setDisplayDate(gregorianCalendarYearDashMonthDashDay: TextualYearMonthDay, gregorianCalendarDayOfMonth: number, displayDayOfWeek: WeekDay): void {
this._date = date; this._gregorianCalendarYearDashMonthDashDay = gregorianCalendarYearDashMonthDashDay;
this._day = day; this._gregorianCalendarDayOfMonth = gregorianCalendarDayOfMonth;
this._dayOfWeek = dayOfWeek; this._displayDayOfWeek = displayDayOfWeek;
} }
public toCreateRequest(clientSessionId: string, actualTime?: number): TransactionCreateRequest { public toCreateRequest(clientSessionId: string, actualTime?: number): TransactionCreateRequest {
+6 -5
View File
@@ -1,3 +1,4 @@
import { type TextualYearMonthDay } from '@/core/datetime.ts';
import { TransactionType } from '@/core/transaction.ts'; import { TransactionType } from '@/core/transaction.ts';
import { TemplateType } from '@/core/template.ts'; import { TemplateType } from '@/core/template.ts';
@@ -8,13 +9,13 @@ export class TransactionTemplate extends Transaction implements TransactionTempl
public name: string; public name: string;
public scheduledFrequencyType?: number; public scheduledFrequencyType?: number;
public scheduledFrequency?: string; public scheduledFrequency?: string;
public scheduledStartDate?: string; public scheduledStartDate?: TextualYearMonthDay;
public scheduledEndDate?: string; public scheduledEndDate?: TextualYearMonthDay;
public scheduledAt?: number; public scheduledAt?: number;
public displayOrder: number; public displayOrder: number;
public hidden: boolean; public hidden: boolean;
private constructor(id: string, templateType: number, name: string, type: number, categoryId: string, timeZone: string | undefined, utcOffset: number, sourceAccountId: string, destinationAccountId: string, sourceAmount: number, destinationAmount: number, hideAmount: boolean, scheduledFrequencyType: number | undefined, scheduledFrequency: string | undefined, scheduledStartDate: string | undefined, scheduledEndDate: string | undefined, scheduledAt: number | undefined, tagIds: string[], comment: string, editable: boolean, displayOrder: number, hidden: boolean) { private constructor(id: string, templateType: number, name: string, type: number, categoryId: string, timeZone: string | undefined, utcOffset: number, sourceAccountId: string, destinationAccountId: string, sourceAmount: number, destinationAmount: number, hideAmount: boolean, scheduledFrequencyType: number | undefined, scheduledFrequency: string | undefined, scheduledStartDate: TextualYearMonthDay | undefined, scheduledEndDate: TextualYearMonthDay | undefined, scheduledAt: number | undefined, tagIds: string[], comment: string, editable: boolean, displayOrder: number, hidden: boolean) {
super(id, '', type, categoryId, 0, timeZone, utcOffset, sourceAccountId, destinationAccountId, sourceAmount, destinationAmount, hideAmount, tagIds, comment, editable); super(id, '', type, categoryId, 0, timeZone, utcOffset, sourceAccountId, destinationAccountId, sourceAmount, destinationAmount, hideAmount, tagIds, comment, editable);
this.templateType = templateType; this.templateType = templateType;
this.name = name; this.name = name;
@@ -211,8 +212,8 @@ export interface TransactionTemplateInfoResponse extends TransactionInfoResponse
readonly name: string; readonly name: string;
readonly scheduledFrequencyType?: number; readonly scheduledFrequencyType?: number;
readonly scheduledFrequency?: string; readonly scheduledFrequency?: string;
readonly scheduledStartDate?: string; readonly scheduledStartDate?: TextualYearMonthDay;
readonly scheduledEndDate?: string; readonly scheduledEndDate?: TextualYearMonthDay;
readonly scheduledAt?: number; readonly scheduledAt?: number;
readonly displayOrder: number; readonly displayOrder: number;
readonly hidden: boolean; readonly hidden: boolean;
+8 -8
View File
@@ -7,7 +7,7 @@ import { useAccountsStore } from './account.ts';
import { useTransactionCategoriesStore } from './transactionCategory.ts'; import { useTransactionCategoriesStore } from './transactionCategory.ts';
import { useExchangeRatesStore } from './exchangeRates.ts'; import { useExchangeRatesStore } from './exchangeRates.ts';
import { type TimeRangeAndDateType, DateRangeScene, DateRange } from '@/core/datetime.ts'; import { type TextualYearMonth, type TimeRangeAndDateType, DateRangeScene, DateRange } from '@/core/datetime.ts';
import { TimezoneTypeForStatistics } from '@/core/timezone.ts'; import { TimezoneTypeForStatistics } from '@/core/timezone.ts';
import { CategoryType } from '@/core/category.ts'; import { CategoryType } from '@/core/category.ts';
import { TransactionTagFilterType } from '@/core/transaction.ts'; import { TransactionTagFilterType } from '@/core/transaction.ts';
@@ -50,7 +50,7 @@ import {
isObjectEmpty, isObjectEmpty,
objectFieldToArrayItem objectFieldToArrayItem
} from '@/lib/common.ts'; } from '@/lib/common.ts';
import { getYearAndMonthFromUnixTime, getDateRangeByDateType } from '@/lib/datetime.ts'; import { getGregorianCalendarYearAndMonthFromUnixTime, getDateRangeByDateType } from '@/lib/datetime.ts';
import { getFinalAccountIdsByFilteredAccountIds } from '@/lib/account.ts'; import { getFinalAccountIdsByFilteredAccountIds } from '@/lib/account.ts';
import { getFinalCategoryIdsByFilteredCategoryIds } from '@/lib/category.ts'; import { getFinalCategoryIdsByFilteredCategoryIds } from '@/lib/category.ts';
import { sortStatisticsItems } from '@/lib/statistics.ts'; import { sortStatisticsItems } from '@/lib/statistics.ts';
@@ -118,8 +118,8 @@ export interface TransactionStatisticsPartialFilter {
categoricalChartEndTime?: number; categoricalChartEndTime?: number;
trendChartType?: number; trendChartType?: number;
trendChartDateType?: number; trendChartDateType?: number;
trendChartStartYearMonth?: string; trendChartStartYearMonth?: TextualYearMonth | '';
trendChartEndYearMonth?: string; trendChartEndYearMonth?: TextualYearMonth | '';
filterAccountIds?: Record<string, boolean>; filterAccountIds?: Record<string, boolean>;
filterCategoryIds?: Record<string, boolean>; filterCategoryIds?: Record<string, boolean>;
tagIds?: string; tagIds?: string;
@@ -136,8 +136,8 @@ export interface TransactionStatisticsFilter extends TransactionStatisticsPartia
categoricalChartEndTime: number; categoricalChartEndTime: number;
trendChartType: number; trendChartType: number;
trendChartDateType: number; trendChartDateType: number;
trendChartStartYearMonth: string; trendChartStartYearMonth: TextualYearMonth | '';
trendChartEndYearMonth: string; trendChartEndYearMonth: TextualYearMonth | '';
filterAccountIds: Record<string, boolean>; filterAccountIds: Record<string, boolean>;
filterCategoryIds: Record<string, boolean>; filterCategoryIds: Record<string, boolean>;
tagIds: string; tagIds: string;
@@ -800,8 +800,8 @@ export const useStatisticsStore = defineStore('statistics', () => {
if (trendChartDateRange) { if (trendChartDateRange) {
transactionStatisticsFilter.value.trendChartDateType = trendChartDateRange.dateType; transactionStatisticsFilter.value.trendChartDateType = trendChartDateRange.dateType;
transactionStatisticsFilter.value.trendChartStartYearMonth = getYearAndMonthFromUnixTime(trendChartDateRange.minTime); transactionStatisticsFilter.value.trendChartStartYearMonth = getGregorianCalendarYearAndMonthFromUnixTime(trendChartDateRange.minTime);
transactionStatisticsFilter.value.trendChartEndYearMonth = getYearAndMonthFromUnixTime(trendChartDateRange.maxTime); transactionStatisticsFilter.value.trendChartEndYearMonth = getGregorianCalendarYearAndMonthFromUnixTime(trendChartDateRange.maxTime);
} }
} }
+15 -21
View File
@@ -10,7 +10,7 @@ import { useStatisticsStore } from './statistics.ts';
import { useExchangeRatesStore } from './exchangeRates.ts'; import { useExchangeRatesStore } from './exchangeRates.ts';
import type { BeforeResolveFunction } from '@/core/base.ts'; import type { BeforeResolveFunction } from '@/core/base.ts';
import { DateRange } from '@/core/datetime.ts'; import { type TextualYearMonth, DateRange } from '@/core/datetime.ts';
import { CategoryType } from '@/core/category.ts'; import { CategoryType } from '@/core/category.ts';
import { TransactionType, TransactionTagFilterType } from '@/core/transaction.ts'; import { TransactionType, TransactionTagFilterType } from '@/core/transaction.ts';
import { TRANSACTION_MIN_AMOUNT, TRANSACTION_MAX_AMOUNT } from '@/consts/transaction.ts'; import { TRANSACTION_MIN_AMOUNT, TRANSACTION_MAX_AMOUNT } from '@/consts/transaction.ts';
@@ -51,13 +51,7 @@ import {
getTimezoneOffsetMinutes, getTimezoneOffsetMinutes,
getBrowserTimezoneOffsetMinutes, getBrowserTimezoneOffsetMinutes,
getActualUnixTimeForStore, getActualUnixTimeForStore,
parseDateFromUnixTime, parseDateTimeFromUnixTime
getShortDate,
getYear,
getMonth,
getYearAndMonth,
getDay,
getDayOfWeekName
} from '@/lib/datetime.ts'; } from '@/lib/datetime.ts';
import { getAmountWithDecimalNumberCount } from '@/lib/numeral.ts'; import { getAmountWithDecimalNumberCount } from '@/lib/numeral.ts';
import { getCurrencyFraction } from '@/lib/currency.ts'; import { getCurrencyFraction } from '@/lib/currency.ts';
@@ -101,7 +95,7 @@ export interface TransactionTotalAmount {
export interface TransactionMonthList { export interface TransactionMonthList {
readonly year: number; readonly year: number;
readonly month: number; // 1-based (1 = January, 12 = December) readonly month: number; // 1-based (1 = January, 12 = December)
readonly yearMonth: string; readonly yearDashMonth: TextualYearMonth;
opened: boolean; opened: boolean;
readonly items: Transaction[]; readonly items: Transaction[];
readonly totalAmount: TransactionTotalAmount; readonly totalAmount: TransactionTotalAmount;
@@ -177,10 +171,10 @@ export const useTransactionsStore = defineStore('transactions', () => {
const item = transactionPageWrapper.items[i]; const item = transactionPageWrapper.items[i];
fillTransactionObject(item, currentUtcOffset); fillTransactionObject(item, currentUtcOffset);
const transactionTime = parseDateFromUnixTime(item.time, item.utcOffset, currentUtcOffset); const transactionTime = parseDateTimeFromUnixTime(item.time, item.utcOffset, currentUtcOffset);
const transactionYear = getYear(transactionTime); const transactionYear = transactionTime.getGregorianCalendarYear();
const transactionMonth = getMonth(transactionTime); const transactionMonth = transactionTime.getGregorianCalendarMonth();
const transactionYearMonth = getYearAndMonth(transactionTime); const transactionYearDashMonth = transactionTime.getGregorianCalendarYearDashMonth();
if (i === 0 && transactions.value.length > 0) { if (i === 0 && transactions.value.length > 0) {
const lastMonthList = transactions.value[transactions.value.length - 1]; const lastMonthList = transactions.value[transactions.value.length - 1];
@@ -216,7 +210,7 @@ export const useTransactionsStore = defineStore('transactions', () => {
const monthList: TransactionMonthList = { const monthList: TransactionMonthList = {
year: transactionYear, year: transactionYear,
month: transactionMonth, month: transactionMonth,
yearMonth: transactionYearMonth, yearDashMonth: transactionYearDashMonth,
opened: autoExpand, opened: autoExpand,
items: [], items: [],
totalAmount: { totalAmount: {
@@ -250,9 +244,9 @@ export const useTransactionsStore = defineStore('transactions', () => {
function updateTransactionInTransactionList({ transaction, defaultCurrency }: { transaction: Transaction, defaultCurrency: string }): void { function updateTransactionInTransactionList({ transaction, defaultCurrency }: { transaction: Transaction, defaultCurrency: string }): void {
const currentUtcOffset = getTimezoneOffsetMinutes(settingsStore.appSettings.timeZone); const currentUtcOffset = getTimezoneOffsetMinutes(settingsStore.appSettings.timeZone);
const transactionTime = parseDateFromUnixTime(transaction.time, transaction.utcOffset, currentUtcOffset); const transactionTime = parseDateTimeFromUnixTime(transaction.time, transaction.utcOffset, currentUtcOffset);
const transactionYear = getYear(transactionTime); const transactionYear = transactionTime.getGregorianCalendarYear();
const transactionMonth = getMonth(transactionTime); const transactionMonth = transactionTime.getGregorianCalendarMonth();
for (let i = 0; i < transactions.value.length; i++) { for (let i = 0; i < transactions.value.length; i++) {
const transactionMonthList = transactions.value[i]; const transactionMonthList = transactions.value[i];
@@ -267,7 +261,7 @@ export const useTransactionsStore = defineStore('transactions', () => {
if (transactionYear !== transactionMonthList.year || if (transactionYear !== transactionMonthList.year ||
transactionMonth !== transactionMonthList.month || transactionMonth !== transactionMonthList.month ||
transaction.day !== transactionMonthList.items[j].day) { transaction.gregorianCalendarDayOfMonth !== transactionMonthList.items[j].gregorianCalendarDayOfMonth) {
transactionListStateInvalid.value = true; transactionListStateInvalid.value = true;
return; return;
} }
@@ -346,7 +340,7 @@ export const useTransactionsStore = defineStore('transactions', () => {
for (let i = 0; i < transactionMonthList.items.length; i++) { for (let i = 0; i < transactionMonthList.items.length; i++) {
const transaction = transactionMonthList.items[i]; const transaction = transactionMonthList.items[i];
const transactionDay = isNumber(transaction.day) ? transaction.day.toString() : '0'; const transactionDay = isNumber(transaction.gregorianCalendarDayOfMonth) ? transaction.gregorianCalendarDayOfMonth.toString() : '0';
let dailyTotalAmount = dailyTotalAmounts[transactionDay]; let dailyTotalAmount = dailyTotalAmounts[transactionDay];
if (!dailyTotalAmount) { if (!dailyTotalAmount) {
@@ -450,8 +444,8 @@ export const useTransactionsStore = defineStore('transactions', () => {
return; return;
} }
const transactionTime = parseDateFromUnixTime(transaction.time, transaction.utcOffset, currentUtcOffset); const transactionTime = parseDateTimeFromUnixTime(transaction.time, transaction.utcOffset, currentUtcOffset);
transaction.setDisplayDate(getShortDate(transactionTime), getDay(transactionTime), getDayOfWeekName(transactionTime)); transaction.setDisplayDate(transactionTime.getGregorianCalendarYearDashMonthDashDay(), transactionTime.getGregorianCalendarDay(), transactionTime.getWeekDay());
if (transaction.sourceAccountId) { if (transaction.sourceAccountId) {
transaction.setSourceAccount(accountsStore.allAccountsMap[transaction.sourceAccountId]); transaction.setSourceAccount(accountsStore.allAccountsMap[transaction.sourceAccountId]);
@@ -23,9 +23,8 @@ import { replaceAll } from '@/lib/common.ts';
import { import {
getUtcOffsetByUtcOffsetMinutes, getUtcOffsetByUtcOffsetMinutes,
getTimezoneOffsetMinutes, getTimezoneOffsetMinutes,
parseDateFromUnixTime, parseDateTimeFromUnixTime,
formatUnixTime, formatUnixTime
getUnixTime
} from '@/lib/datetime.ts'; } from '@/lib/datetime.ts';
export function useReconciliationStatementPageBase() { export function useReconciliationStatementPageBase() {
@@ -132,8 +131,7 @@ export function useReconciliationStatementPageBase() {
} }
function getDisplayDateTime(transaction: TransactionReconciliationStatementResponseItem): string { function getDisplayDateTime(transaction: TransactionReconciliationStatementResponseItem): string {
const transactionTime = getUnixTime(parseDateFromUnixTime(transaction.time, transaction.utcOffset, currentTimezoneOffsetMinutes.value)); return formatUnixTimeToLongDateTime(transaction.time, transaction.utcOffset, currentTimezoneOffsetMinutes.value);
return formatUnixTimeToLongDateTime(transactionTime);
} }
function getDisplayDate(transaction: TransactionReconciliationStatementResponseItem): string { function getDisplayDate(transaction: TransactionReconciliationStatementResponseItem): string {
@@ -210,7 +208,7 @@ export function useReconciliationStatementPageBase() {
const transactions = reconciliationStatements.value?.transactions ?? []; const transactions = reconciliationStatements.value?.transactions ?? [];
const rows = transactions.map(transaction => { const rows = transactions.map(transaction => {
const transactionTime = getUnixTime(parseDateFromUnixTime(transaction.time, transaction.utcOffset, currentTimezoneOffsetMinutes.value)); const transactionTime = parseDateTimeFromUnixTime(transaction.time, transaction.utcOffset, currentTimezoneOffsetMinutes.value).getUnixTime();
const type = getDisplayTransactionType(transaction); const type = getDisplayTransactionType(transaction);
let categoryName = allCategoriesMap.value[transaction.categoryId]?.name || ''; let categoryName = allCategoriesMap.value[transaction.categoryId]?.name || '';
let displayAmount = formatAmountToWesternArabicNumeralsWithoutDigitGrouping(transaction.sourceAmount); let displayAmount = formatAmountToWesternArabicNumeralsWithoutDigitGrouping(transaction.sourceAmount);
@@ -10,7 +10,7 @@ import { useTransactionTagsStore } from '@/stores/transactionTag.ts';
import { type TransactionListFilter, type TransactionMonthList, useTransactionsStore } from '@/stores/transaction.ts'; import { type TransactionListFilter, type TransactionMonthList, useTransactionsStore } from '@/stores/transaction.ts';
import type { TypeAndName } from '@/core/base.ts'; import type { TypeAndName } from '@/core/base.ts';
import { type LocalizedDateRange, type WeekDayValue, DateRange, DateRangeScene } from '@/core/datetime.ts'; import { type TextualYearMonthDay, type Year0BasedMonth, type LocalizedDateRange, type WeekDayValue, DateRange, DateRangeScene } from '@/core/datetime.ts';
import { AccountType } from '@/core/account.ts'; import { AccountType } from '@/core/account.ts';
import { TransactionType } from '@/core/transaction.ts'; import { TransactionType } from '@/core/transaction.ts';
import { DISPLAY_HIDDEN_AMOUNT, INCOMPLETE_AMOUNT_SUFFIX } from '@/consts/numeral.ts'; import { DISPLAY_HIDDEN_AMOUNT, INCOMPLETE_AMOUNT_SUFFIX } from '@/consts/numeral.ts';
@@ -28,14 +28,10 @@ import {
getLocalDatetimeFromUnixTime, getLocalDatetimeFromUnixTime,
getActualUnixTimeForStore, getActualUnixTimeForStore,
getDummyUnixTimeForLocalUsage, getDummyUnixTimeForLocalUsage,
getCurrentYearAndMonth, getCurrentDateTime,
parseDateFromUnixTime, parseDateTimeFromUnixTime,
getYearAndMonth,
getYear,
getMonth,
getYearMonthFirstUnixTime, getYearMonthFirstUnixTime,
getDay, getUnixTimeFromLocalDatetime,
getUnixTime,
isDateRangeMatchOneMonth isDateRangeMatchOneMonth
} from '@/lib/datetime.ts'; } from '@/lib/datetime.ts';
@@ -99,7 +95,7 @@ export function useTransactionListPageBase() {
const loading = ref<boolean>(true); const loading = ref<boolean>(true);
const customMinDatetime = ref<number>(0); const customMinDatetime = ref<number>(0);
const customMaxDatetime = ref<number>(0); const customMaxDatetime = ref<number>(0);
const currentCalendarDate = ref<string>(''); const currentCalendarDate = ref<TextualYearMonthDay | ''>('');
const currentTimezoneOffsetMinutes = computed<number>(() => getTimezoneOffsetMinutes(settingsStore.appSettings.timeZone)); const currentTimezoneOffsetMinutes = computed<number>(() => getTimezoneOffsetMinutes(settingsStore.appSettings.timeZone));
const firstDayOfWeek = computed<WeekDayValue>(() => userStore.currentUserFirstDayOfWeek); const firstDayOfWeek = computed<WeekDayValue>(() => userStore.currentUserFirstDayOfWeek);
@@ -175,12 +171,12 @@ export function useTransactionListPageBase() {
const queryMinTime = computed<string>(() => formatUnixTimeToLongDateTime(query.value.minTime)); const queryMinTime = computed<string>(() => formatUnixTimeToLongDateTime(query.value.minTime));
const queryMaxTime = computed<string>(() => formatUnixTimeToLongDateTime(query.value.maxTime)); const queryMaxTime = computed<string>(() => formatUnixTimeToLongDateTime(query.value.maxTime));
const queryMonthlyData = computed<boolean>(() => isDateRangeMatchOneMonth(query.value.minTime, query.value.maxTime)); const queryMonthlyData = computed<boolean>(() => isDateRangeMatchOneMonth(query.value.minTime, query.value.maxTime));
const queryMonth = computed<string>(() => { const queryMonth = computed<Year0BasedMonth>(() => {
if (!query.value.minTime || !query.value.maxTime) { if (!query.value.minTime || !query.value.maxTime) {
return getCurrentYearAndMonth(); return getCurrentDateTime().toGregorianCalendarYear0BasedMonth();
} }
return getYearAndMonth(parseDateFromUnixTime(query.value.minTime)); return parseDateTimeFromUnixTime(query.value.minTime).toGregorianCalendarYear0BasedMonth();
}); });
const queryAllFilterCategoryIds = computed<Record<string, boolean>>(() => transactionsStore.allFilterCategoryIds); const queryAllFilterCategoryIds = computed<Record<string, boolean>>(() => transactionsStore.allFilterCategoryIds);
@@ -248,9 +244,9 @@ export function useTransactionListPageBase() {
return null; return null;
} }
const currentMonthMinDate = parseDateFromUnixTime(query.value.minTime); const currentMonthMinDate = parseDateTimeFromUnixTime(query.value.minTime);
const currentYear = getYear(currentMonthMinDate); const currentYear = currentMonthMinDate.getGregorianCalendarYear();
const currentMonth = getMonth(currentMonthMinDate); const currentMonth = currentMonthMinDate.getGregorianCalendarMonth();
for (let i = 0; i < allTransactions.length; i++) { for (let i = 0; i < allTransactions.length; i++) {
if (allTransactions[i].year === currentYear && allTransactions[i].month === currentMonth) { if (allTransactions[i].year === currentYear && allTransactions[i].month === currentMonth) {
@@ -262,8 +258,8 @@ export function useTransactionListPageBase() {
}); });
function noTransactionInMonthDay(date: Date): boolean { function noTransactionInMonthDay(date: Date): boolean {
const dateTime = parseDateFromUnixTime(getActualUnixTimeForStore(getUnixTime(date), getTimezoneOffsetMinutes(), getBrowserTimezoneOffsetMinutes())); const dateTime = parseDateTimeFromUnixTime(getActualUnixTimeForStore(getUnixTimeFromLocalDatetime(date), getTimezoneOffsetMinutes(), getBrowserTimezoneOffsetMinutes()));
return !currentMonthTransactionData.value || !currentMonthTransactionData.value.dailyTotalAmounts || !currentMonthTransactionData.value.dailyTotalAmounts[getDay(dateTime)]; return !currentMonthTransactionData.value || !currentMonthTransactionData.value.dailyTotalAmounts || !currentMonthTransactionData.value.dailyTotalAmounts[dateTime.getGregorianCalendarDay()];
} }
const canAddTransaction = computed<boolean>(() => { const canAddTransaction = computed<boolean>(() => {
@@ -291,12 +287,11 @@ export function useTransactionListPageBase() {
} }
function getDisplayLongDate(transaction: Transaction): string { function getDisplayLongDate(transaction: Transaction): string {
const transactionTime = getUnixTime(parseDateFromUnixTime(transaction.time, transaction.utcOffset, currentTimezoneOffsetMinutes.value)); return formatUnixTimeToLongDate(transaction.time, transaction.utcOffset, currentTimezoneOffsetMinutes.value);
return formatUnixTimeToLongDate(transactionTime);
} }
function getDisplayLongYearMonth(transactionMonthList: TransactionMonthList): string { function getDisplayLongYearMonth(transactionMonthList: TransactionMonthList): string {
return formatUnixTimeToLongYearMonth(getYearMonthFirstUnixTime(transactionMonthList.yearMonth)); return formatUnixTimeToLongYearMonth(getYearMonthFirstUnixTime(transactionMonthList.yearDashMonth));
} }
function getDisplayTimezone(transaction: Transaction): string { function getDisplayTimezone(transaction: Transaction): string {
@@ -41,10 +41,7 @@ import { DISPLAY_HIDDEN_AMOUNT, INCOMPLETE_AMOUNT_SUFFIX } from '@/consts/numera
import { type TransactionMonthlyIncomeAndExpenseData } from '@/models/transaction.ts'; import { type TransactionMonthlyIncomeAndExpenseData } from '@/models/transaction.ts';
import { import { parseDateTimeFromUnixTime } from '@/lib/datetime.ts';
parseDateFromUnixTime,
getMonthName
} from '@/lib/datetime.ts';
import { getExpenseAndIncomeAmountColor } from '@/lib/ui/common.ts'; import { getExpenseAndIncomeAmountColor } from '@/lib/ui/common.ts';
export interface MonthlyIncomeAndExpenseCardClickEvent { export interface MonthlyIncomeAndExpenseCardClickEvent {
@@ -100,7 +97,7 @@ const chartOptions = computed<object>(() => {
if (props.data) { if (props.data) {
for (let i = 0; i < props.data.length; i++) { for (let i = 0; i < props.data.length; i++) {
const item = props.data[i]; const item = props.data[i];
const month = getMonthName(parseDateFromUnixTime(item.monthStartTime)); const month = parseDateTimeFromUnixTime(item.monthStartTime).getGregorianCalendarMonthName();
monthNames.push(getMonthShortName(month)); monthNames.push(getMonthShortName(month));
incomeAmounts.push(item.incomeAmount); incomeAmounts.push(item.incomeAmount);
@@ -358,7 +358,7 @@ import { useTransactionCategoriesStore } from '@/stores/transactionCategory.ts';
import { type TransactionStatisticsPartialFilter, useStatisticsStore } from '@/stores/statistics.ts'; import { type TransactionStatisticsPartialFilter, useStatisticsStore } from '@/stores/statistics.ts';
import type { TypeAndDisplayName } from '@/core/base.ts'; import type { TypeAndDisplayName } from '@/core/base.ts';
import { type TimeRangeAndDateType, DateRangeScene, DateRange } from '@/core/datetime.ts'; import { type TextualYearMonth, type TimeRangeAndDateType, DateRangeScene, DateRange } from '@/core/datetime.ts';
import { ThemeType } from '@/core/theme.ts'; import { ThemeType } from '@/core/theme.ts';
import { import {
StatisticsAnalysisType, StatisticsAnalysisType,
@@ -375,7 +375,7 @@ import {
arrayItemToObjectField arrayItemToObjectField
} from '@/lib/common.ts'; } from '@/lib/common.ts';
import { import {
getYearAndMonthFromUnixTime, getGregorianCalendarYearAndMonthFromUnixTime,
getYearMonthFirstUnixTime, getYearMonthFirstUnixTime,
getYearMonthLastUnixTime, getYearMonthLastUnixTime,
getShiftedDateRangeAndDateType, getShiftedDateRangeAndDateType,
@@ -407,8 +407,8 @@ interface TransactionStatisticsProps {
initChartDataType?: string, initChartDataType?: string,
initChartType?: string, initChartType?: string,
initChartDateType?: string, initChartDateType?: string,
initStartTime?: string, initStartTime?: TextualYearMonth | '',
initEndTime?: string, initEndTime?: TextualYearMonth | '',
initFilterAccountIds?: string, initFilterAccountIds?: string,
initFilterCategoryIds?: string, initFilterCategoryIds?: string,
initTagIds?: string, initTagIds?: string,
@@ -814,8 +814,8 @@ function setDateFilter(dateType: number): void {
} else if (analysisType.value === StatisticsAnalysisType.TrendAnalysis) { } else if (analysisType.value === StatisticsAnalysisType.TrendAnalysis) {
changed = statisticsStore.updateTransactionStatisticsFilter({ changed = statisticsStore.updateTransactionStatisticsFilter({
trendChartDateType: dateRange.dateType, trendChartDateType: dateRange.dateType,
trendChartStartYearMonth: getYearAndMonthFromUnixTime(dateRange.minTime), trendChartStartYearMonth: getGregorianCalendarYearAndMonthFromUnixTime(dateRange.minTime),
trendChartEndYearMonth: getYearAndMonthFromUnixTime(dateRange.maxTime) trendChartEndYearMonth: getGregorianCalendarYearAndMonthFromUnixTime(dateRange.maxTime)
}); });
} }
@@ -826,7 +826,7 @@ function setDateFilter(dateType: number): void {
} }
} }
function setCustomDateFilter(startTime: number | string, endTime: number | string): void { function setCustomDateFilter(startTime: number | TextualYearMonth, endTime: number | TextualYearMonth): void {
if (!startTime || !endTime) { if (!startTime || !endTime) {
return; return;
} }
@@ -882,8 +882,8 @@ function shiftDateRange(scale: number): void {
changed = statisticsStore.updateTransactionStatisticsFilter({ changed = statisticsStore.updateTransactionStatisticsFilter({
trendChartDateType: newDateRange.dateType, trendChartDateType: newDateRange.dateType,
trendChartStartYearMonth: getYearAndMonthFromUnixTime(newDateRange.minTime), trendChartStartYearMonth: getGregorianCalendarYearAndMonthFromUnixTime(newDateRange.minTime),
trendChartEndYearMonth: getYearAndMonthFromUnixTime(newDateRange.maxTime) trendChartEndYearMonth: getGregorianCalendarYearAndMonthFromUnixTime(newDateRange.maxTime)
}); });
} }
@@ -992,8 +992,8 @@ onBeforeRouteUpdate((to) => {
initChartDataType: (to.query['chartDataType'] as string | null) || undefined, initChartDataType: (to.query['chartDataType'] as string | null) || undefined,
initChartType: (to.query['chartType'] as string | null) || undefined, initChartType: (to.query['chartType'] as string | null) || undefined,
initChartDateType: (to.query['chartDateType'] as string | null) || undefined, initChartDateType: (to.query['chartDateType'] as string | null) || undefined,
initStartTime: (to.query['startTime'] as string | null) || undefined, initStartTime: (to.query['startTime'] as TextualYearMonth | null) || undefined,
initEndTime: (to.query['endTime'] as string | null) || undefined, initEndTime: (to.query['endTime'] as TextualYearMonth | null) || undefined,
initFilterAccountIds: (to.query['filterAccountIds'] as string | null) || undefined, initFilterAccountIds: (to.query['filterAccountIds'] as string | null) || undefined,
initFilterCategoryIds: (to.query['filterCategoryIds'] as string | null) || undefined, initFilterCategoryIds: (to.query['filterCategoryIds'] as string | null) || undefined,
initTagIds: (to.query['tagIds'] as string | null) || undefined, initTagIds: (to.query['tagIds'] as string | null) || undefined,
+11 -12
View File
@@ -165,7 +165,7 @@
</v-card-text> </v-card-text>
<v-card-text class="transaction-calendar-container pt-0" v-if="pageType === TransactionListPageType.Calendar.type"> <v-card-text class="transaction-calendar-container pt-0" v-if="pageType === TransactionListPageType.Calendar.type">
<vue-date-picker inline auto-apply model-type="yyyy-M-d" <vue-date-picker inline auto-apply model-type="yyyy-MM-dd"
month-name-format="long" month-name-format="long"
:config="{ noSwipe: true }" :config="{ noSwipe: true }"
:readonly="loading" :readonly="loading"
@@ -545,13 +545,13 @@
:class="{ 'disabled': loading, 'has-bottom-border': idx < transactions.length - 1 }" :class="{ 'disabled': loading, 'has-bottom-border': idx < transactions.length - 1 }"
v-for="(transaction, idx) in transactions"> v-for="(transaction, idx) in transactions">
<tr class="transaction-list-row-date no-hover text-sm" <tr class="transaction-list-row-date no-hover text-sm"
v-if="pageType === TransactionListPageType.List.type && (idx === 0 || (idx > 0 && (transaction.date !== transactions[idx - 1].date)))"> v-if="pageType === TransactionListPageType.List.type && (idx === 0 || (idx > 0 && (transaction.gregorianCalendarYearDashMonthDashDay !== transactions[idx - 1].gregorianCalendarYearDashMonthDashDay)))">
<td :colspan="showTagInTransactionListPage ? 6 : 5" class="font-weight-bold"> <td :colspan="showTagInTransactionListPage ? 6 : 5" class="font-weight-bold">
<div class="d-flex align-center"> <div class="d-flex align-center">
<span>{{ getDisplayLongDate(transaction) }}</span> <span>{{ getDisplayLongDate(transaction) }}</span>
<v-chip class="ms-1" color="default" size="x-small" <v-chip class="ms-1" color="default" size="x-small"
v-if="transaction.dayOfWeek"> v-if="transaction.displayDayOfWeek">
{{ getWeekdayLongName(transaction.dayOfWeek) }} {{ getWeekdayLongName(transaction.displayDayOfWeek) }}
</v-chip> </v-chip>
</div> </div>
</td> </td>
@@ -689,6 +689,7 @@ import { useDesktopPageStore } from '@/stores/desktopPage.ts';
import type { TypeAndDisplayName } from '@/core/base.ts'; import type { TypeAndDisplayName } from '@/core/base.ts';
import { import {
type Year0BasedMonth,
type LocalizedRecentMonthDateRange, type LocalizedRecentMonthDateRange,
type TimeRangeAndDateType, type TimeRangeAndDateType,
DateRangeScene, DateRangeScene,
@@ -710,9 +711,7 @@ import {
} from '@/lib/common.ts'; } from '@/lib/common.ts';
import { import {
getCurrentUnixTime, getCurrentUnixTime,
parseDateFromUnixTime, parseDateTimeFromUnixTime,
getYear,
getMonth,
getBrowserTimezoneOffsetMinutes, getBrowserTimezoneOffsetMinutes,
getActualUnixTimeForStore, getActualUnixTimeForStore,
getDayFirstUnixTimeBySpecifiedUnixTime, getDayFirstUnixTimeBySpecifiedUnixTime,
@@ -960,7 +959,7 @@ const transactions = computed<Transaction[]>(() => {
for (let i = 0; i < transactionData.items.length; i++) { for (let i = 0; i < transactionData.items.length; i++) {
const transaction = transactionData.items[i]; const transaction = transactionData.items[i];
if (transaction.date === currentCalendarDate.value) { if (transaction.gregorianCalendarYearDashMonthDashDay === currentCalendarDate.value) {
transactions.push(transaction); transactions.push(transaction);
} }
} }
@@ -1208,9 +1207,9 @@ function reload(force: boolean, init: boolean): void {
} }
if (queryMonthlyData.value) { if (queryMonthlyData.value) {
const currentMonthMinDate = parseDateFromUnixTime(query.value.minTime); const currentMonthMinDate = parseDateTimeFromUnixTime(query.value.minTime);
const currentYear = getYear(currentMonthMinDate); const currentYear = currentMonthMinDate.getGregorianCalendarYear();
const currentMonth = getMonth(currentMonthMinDate); const currentMonth = currentMonthMinDate.getGregorianCalendarMonth();
return transactionsStore.loadMonthlyAllTransactions({ return transactionsStore.loadMonthlyAllTransactions({
year: currentYear, year: currentYear,
@@ -1362,7 +1361,7 @@ function changeCustomDateFilter(minTime: number, maxTime: number): void {
updateUrlWhenChanged(changed); updateUrlWhenChanged(changed);
} }
function changeCustomMonthDateFilter(yearMonth: string): void { function changeCustomMonthDateFilter(yearMonth: Year0BasedMonth): void {
if (!yearMonth) { if (!yearMonth) {
return; return;
} }
@@ -936,8 +936,6 @@ import {
import { generateRandomUUID } from '@/lib/misc.ts'; import { generateRandomUUID } from '@/lib/misc.ts';
import logger from '@/lib/logger.ts'; import logger from '@/lib/logger.ts';
import { import {
parseDateFromUnixTime,
getUnixTime,
getUtcOffsetByUtcOffsetMinutes, getUtcOffsetByUtcOffsetMinutes,
getTimezoneOffsetMinutes getTimezoneOffsetMinutes
} from '@/lib/datetime.ts'; } from '@/lib/datetime.ts';
@@ -1655,8 +1653,7 @@ function isTagValid(tagIds: string[], tagIndex: number): boolean {
} }
function getDisplayDateTime(transaction: ImportTransaction): string { function getDisplayDateTime(transaction: ImportTransaction): string {
const transactionTime = getUnixTime(parseDateFromUnixTime(transaction.time, transaction.utcOffset, currentTimezoneOffsetMinutes.value)); return formatUnixTimeToLongDateTime(transaction.time, transaction.utcOffset, currentTimezoneOffsetMinutes.value);
return formatUnixTimeToLongDateTime(transactionTime);
} }
function getDisplayTimezone(transaction: ImportTransaction): string { function getDisplayTimezone(transaction: ImportTransaction): string {
@@ -125,7 +125,7 @@ import { useSettingsStore } from '@/stores/setting.ts';
import { TextDirection } from '@/core/text.ts'; import { TextDirection } from '@/core/text.ts';
import { FontSize } from '@/core/font.ts'; import { FontSize } from '@/core/font.ts';
import { getLocalDatetimeFromUnixTime, getCurrentUnixTime, getDay, getDayOfWeekName } from '@/lib/datetime.ts'; import { parseDateTimeFromUnixTime, getCurrentUnixTime } from '@/lib/datetime.ts';
import { setAppFontSize, getFontSizePreviewClassName } from '@/lib/ui/mobile.ts'; import { setAppFontSize, getFontSizePreviewClassName } from '@/lib/ui/mobile.ts';
const props = defineProps<{ const props = defineProps<{
@@ -149,8 +149,8 @@ const fontSize = ref<number>(settingsStore.appSettings.fontSize);
const textDirection = computed<string>(() => getCurrentLanguageTextDirection()); const textDirection = computed<string>(() => getCurrentLanguageTextDirection());
const fontSizePreviewClassName = computed<string>(() => getFontSizePreviewClassName(fontSize.value)); const fontSizePreviewClassName = computed<string>(() => getFontSizePreviewClassName(fontSize.value));
const currentLongYearMonth = computed<string>(() => formatUnixTimeToLongYearMonth(currentUnixTime.value)); const currentLongYearMonth = computed<string>(() => formatUnixTimeToLongYearMonth(currentUnixTime.value));
const currentDayOfMonth = computed<number>(() => getDay(getLocalDatetimeFromUnixTime(currentUnixTime.value))); const currentDayOfMonth = computed<number>(() => parseDateTimeFromUnixTime(currentUnixTime.value).getLocalizedCalendarDay());
const currentDayOfWeek = computed<string>(() => getWeekdayShortName(getDayOfWeekName(getLocalDatetimeFromUnixTime(currentUnixTime.value)))); const currentDayOfWeek = computed<string>(() => getWeekdayShortName(parseDateTimeFromUnixTime(currentUnixTime.value).getWeekDay()));
const currentShortTime = computed<string>(() => formatUnixTimeToShortTime(currentUnixTime.value)); const currentShortTime = computed<string>(() => formatUnixTimeToShortTime(currentUnixTime.value));
function getFontSizeName(): string { function getFontSizeName(): string {
@@ -344,7 +344,7 @@ import { useStatisticsStore } from '@/stores/statistics.ts';
import type { TypeAndDisplayName } from '@/core/base.ts'; import type { TypeAndDisplayName } from '@/core/base.ts';
import { TextDirection } from '@/core/text.ts'; import { TextDirection } from '@/core/text.ts';
import { type TimeRangeAndDateType, DateRangeScene, DateRange } from '@/core/datetime.ts'; import { type TextualYearMonth, type TimeRangeAndDateType, DateRangeScene, DateRange } from '@/core/datetime.ts';
import { import {
StatisticsAnalysisType, StatisticsAnalysisType,
CategoricalChartType, CategoricalChartType,
@@ -355,7 +355,7 @@ import {
import { isString, isNumber } from '@/lib/common.ts'; import { isString, isNumber } from '@/lib/common.ts';
import { import {
getYearAndMonthFromUnixTime, getGregorianCalendarYearAndMonthFromUnixTime,
getYearMonthFirstUnixTime, getYearMonthFirstUnixTime,
getYearMonthLastUnixTime, getYearMonthLastUnixTime,
getShiftedDateRangeAndDateType, getShiftedDateRangeAndDateType,
@@ -626,8 +626,8 @@ function setDateFilter(dateType: number): void {
} else if (analysisType.value === StatisticsAnalysisType.TrendAnalysis) { } else if (analysisType.value === StatisticsAnalysisType.TrendAnalysis) {
changed = statisticsStore.updateTransactionStatisticsFilter({ changed = statisticsStore.updateTransactionStatisticsFilter({
trendChartDateType: dateRange.dateType, trendChartDateType: dateRange.dateType,
trendChartStartYearMonth: getYearAndMonthFromUnixTime(dateRange.minTime), trendChartStartYearMonth: getGregorianCalendarYearAndMonthFromUnixTime(dateRange.minTime),
trendChartEndYearMonth: getYearAndMonthFromUnixTime(dateRange.maxTime) trendChartEndYearMonth: getGregorianCalendarYearAndMonthFromUnixTime(dateRange.maxTime)
}); });
} }
@@ -638,7 +638,7 @@ function setDateFilter(dateType: number): void {
} }
} }
function setCustomDateFilter(startTime: number | string, endTime: number | string): void { function setCustomDateFilter(startTime: number | TextualYearMonth, endTime: number | TextualYearMonth): void {
if (!startTime || !endTime) { if (!startTime || !endTime) {
return; return;
} }
@@ -692,8 +692,8 @@ function shiftDateRange(scale: number): void {
changed = statisticsStore.updateTransactionStatisticsFilter({ changed = statisticsStore.updateTransactionStatisticsFilter({
trendChartDateType: newDateRange.dateType, trendChartDateType: newDateRange.dateType,
trendChartStartYearMonth: getYearAndMonthFromUnixTime(newDateRange.minTime), trendChartStartYearMonth: getGregorianCalendarYearAndMonthFromUnixTime(newDateRange.minTime),
trendChartEndYearMonth: getYearAndMonthFromUnixTime(newDateRange.maxTime) trendChartEndYearMonth: getGregorianCalendarYearAndMonthFromUnixTime(newDateRange.maxTime)
}); });
} }
+3 -3
View File
@@ -536,7 +536,7 @@ const {
getMultiWeekdayLongNames, getMultiWeekdayLongNames,
formatUnixTimeToLongDate, formatUnixTimeToLongDate,
formatUnixTimeToLongTime, formatUnixTimeToLongTime,
formatDateToLongDate formatGregorianCalendarYearDashMonthDashDayToLongDate
} = useI18n(); } = useI18n();
const { showAlert, showConfirm, showToast, routeBackOnError } = useI18nUIComponents(); const { showAlert, showConfirm, showToast, routeBackOnError } = useI18nUIComponents();
@@ -754,7 +754,7 @@ const transactionDisplayScheduledStartDate = computed<string>(() => {
const template = transaction.value as TransactionTemplate; const template = transaction.value as TransactionTemplate;
if (template.scheduledStartDate) { if (template.scheduledStartDate) {
return formatDateToLongDate(template.scheduledStartDate); return formatGregorianCalendarYearDashMonthDashDayToLongDate(template.scheduledStartDate);
} else { } else {
return tt('No limit'); return tt('No limit');
} }
@@ -768,7 +768,7 @@ const transactionDisplayScheduledEndDate = computed<string>(() => {
const template = transaction.value as TransactionTemplate; const template = transaction.value as TransactionTemplate;
if (template.scheduledEndDate) { if (template.scheduledEndDate) {
return formatDateToLongDate(template.scheduledEndDate); return formatGregorianCalendarYearDashMonthDashDayToLongDate(template.scheduledEndDate);
} else { } else {
return tt('No limit'); return tt('No limit');
} }
+36 -36
View File
@@ -67,7 +67,7 @@
</f7-toolbar> </f7-toolbar>
<f7-block class="transaction-calendar-container margin-vertical" v-if="pageType === TransactionListPageType.Calendar.type"> <f7-block class="transaction-calendar-container margin-vertical" v-if="pageType === TransactionListPageType.Calendar.type">
<vue-date-picker inline auto-apply model-type="yyyy-M-d" <vue-date-picker inline auto-apply model-type="yyyy-MM-dd"
month-name-format="long" month-name-format="long"
class="justify-content-center" class="justify-content-center"
:config="{ noSwipe: true }" :config="{ noSwipe: true }"
@@ -174,13 +174,13 @@
</f7-list> </f7-list>
<f7-block class="combination-list-wrapper margin-vertical" :class="{ 'no-accordion-toggle': pageType !== TransactionListPageType.List.type }" <f7-block class="combination-list-wrapper margin-vertical" :class="{ 'no-accordion-toggle': pageType !== TransactionListPageType.List.type }"
:key="transactionMonthList.yearMonth" v-for="(transactionMonthList) in transactions"> :key="transactionMonthList.yearDashMonth" v-for="(transactionMonthList) in transactions">
<f7-accordion-item :opened="transactionMonthList.opened" <f7-accordion-item :opened="transactionMonthList.opened"
@accordion:open="collapseTransactionMonthList(transactionMonthList, false)" @accordion:open="collapseTransactionMonthList(transactionMonthList, false)"
@accordion:opened="onTransactionMonthListCollapseStateChanged" @accordion:opened="onTransactionMonthListCollapseStateChanged"
@accordion:close="collapseTransactionMonthList(transactionMonthList, true)" @accordion:close="collapseTransactionMonthList(transactionMonthList, true)"
@accordion:closed="onTransactionMonthListCollapseStateChanged"> @accordion:closed="onTransactionMonthListCollapseStateChanged">
<f7-block-title :id="getTransactionMonthTitleDomId(transactionMonthList.yearMonth)" v-if="pageType === TransactionListPageType.List.type"> <f7-block-title :id="getTransactionMonthTitleDomId(transactionMonthList.yearDashMonth)" v-if="pageType === TransactionListPageType.List.type">
<f7-accordion-toggle> <f7-accordion-toggle>
<f7-list strong inset dividers media-list <f7-list strong inset dividers media-list
class="transaction-amount-list combination-list-header" class="transaction-amount-list combination-list-header"
@@ -209,7 +209,7 @@
v-if="isTransactionMonthListInvisible(transactionMonthList)" /> v-if="isTransactionMonthListInvisible(transactionMonthList)" />
<f7-list strong inset dividers media-list accordion-list <f7-list strong inset dividers media-list accordion-list
class="transaction-info-list transaction-month-list combination-list-content" class="transaction-info-list transaction-month-list combination-list-content"
:id="getTransactionMonthListDomId(transactionMonthList.yearMonth)" :id="getTransactionMonthListDomId(transactionMonthList.yearDashMonth)"
v-if="!isTransactionMonthListInvisible(transactionMonthList)" v-if="!isTransactionMonthListInvisible(transactionMonthList)"
> >
<f7-list-item swipeout chevron-center accordion-item <f7-list-item swipeout chevron-center accordion-item
@@ -222,10 +222,10 @@
<template #media> <template #media>
<div class="display-flex flex-direction-column transaction-date" :style="getTransactionDateStyle(transaction, idx > 0 ? transactionMonthList.items[idx - 1] : null)"> <div class="display-flex flex-direction-column transaction-date" :style="getTransactionDateStyle(transaction, idx > 0 ? transactionMonthList.items[idx - 1] : null)">
<span class="transaction-day full-line flex-direction-column"> <span class="transaction-day full-line flex-direction-column">
{{ transaction.day }} {{ transaction.gregorianCalendarDayOfMonth }}
</span> </span>
<span class="transaction-day-of-week full-line flex-direction-column" v-if="transaction.dayOfWeek"> <span class="transaction-day-of-week full-line flex-direction-column" v-if="transaction.displayDayOfWeek">
{{ getWeekdayShortName(transaction.dayOfWeek) }} {{ getWeekdayShortName(transaction.displayDayOfWeek) }}
</span> </span>
</div> </div>
</template> </template>
@@ -620,9 +620,11 @@ import { type TransactionMonthList, useTransactionsStore } from '@/stores/transa
import type { TypeAndDisplayName } from '@/core/base.ts'; import type { TypeAndDisplayName } from '@/core/base.ts';
import { TextDirection } from '@/core/text.ts'; import { TextDirection } from '@/core/text.ts';
import { import {
type TextualYearMonth,
type Year0BasedMonth,
type TimeRangeAndDateType, type TimeRangeAndDateType,
DateRangeScene, DateRangeScene,
DateRange, DateRange
} from '@/core/datetime.ts'; } from '@/core/datetime.ts';
import { AmountFilterType } from '@/core/numeral.ts'; import { AmountFilterType } from '@/core/numeral.ts';
import { TransactionType } from '@/core/transaction.ts'; import { TransactionType } from '@/core/transaction.ts';
@@ -635,11 +637,9 @@ import {
} from '@/lib/common.ts'; } from '@/lib/common.ts';
import { import {
getCurrentUnixTime, getCurrentUnixTime,
parseDateFromUnixTime, parseDateTimeFromUnixTime,
getBrowserTimezoneOffsetMinutes, getBrowserTimezoneOffsetMinutes,
getActualUnixTimeForStore, getActualUnixTimeForStore,
getYear,
getMonth,
getDayFirstUnixTimeBySpecifiedUnixTime, getDayFirstUnixTimeBySpecifiedUnixTime,
getYearMonthFirstUnixTime, getYearMonthFirstUnixTime,
getYearMonthLastUnixTime, getYearMonthLastUnixTime,
@@ -731,8 +731,8 @@ const transactionsStore = useTransactionsStore();
const loadingError = ref<unknown | null>(null); const loadingError = ref<unknown | null>(null);
const loadingMore = ref<boolean>(false); const loadingMore = ref<boolean>(false);
const transactionToDelete = ref<Transaction | null>(null); const transactionToDelete = ref<Transaction | null>(null);
const transactionInvisibleYearMonths = ref<Record<string, boolean>>({}); const transactionInvisibleYearMonths = ref<Record<TextualYearMonth, boolean>>({});
const transactionYearMonthListHeights = ref<Record<string, number>>({}); const transactionYearMonthListHeights = ref<Record<TextualYearMonth, number>>({});
const showTransactionListPageTypePopover = ref<boolean>(false); const showTransactionListPageTypePopover = ref<boolean>(false);
const showDatePopover = ref<boolean>(false); const showDatePopover = ref<boolean>(false);
const showCategoryPopover = ref<boolean>(false); const showCategoryPopover = ref<boolean>(false);
@@ -768,7 +768,7 @@ const transactions = computed<TransactionMonthList[]>(() => {
for (let i = 0; i < transactionData.items.length; i++) { for (let i = 0; i < transactionData.items.length; i++) {
const transaction = transactionData.items[i]; const transaction = transactionData.items[i];
if (transaction.date === currentCalendarDate.value) { if (transaction.gregorianCalendarYearDashMonthDashDay === currentCalendarDate.value) {
transactions.push(transaction); transactions.push(transaction);
} }
} }
@@ -776,7 +776,7 @@ const transactions = computed<TransactionMonthList[]>(() => {
const dailyTransactionList: TransactionMonthList = { const dailyTransactionList: TransactionMonthList = {
year: currentMonthTransactionData.value.year, year: currentMonthTransactionData.value.year,
month: currentMonthTransactionData.value.month, month: currentMonthTransactionData.value.month,
yearMonth: currentMonthTransactionData.value.yearMonth, yearDashMonth: currentMonthTransactionData.value.yearDashMonth,
opened: true, opened: true,
items: transactions, items: transactions,
totalAmount: { totalAmount: {
@@ -809,11 +809,11 @@ const noTransaction = computed<boolean>(() => {
const hasMoreTransaction = computed<boolean>(() => transactionsStore.hasMoreTransaction); const hasMoreTransaction = computed<boolean>(() => transactionsStore.hasMoreTransaction);
function getTransactionMonthTitleDomId(yearMonth: string): string { function getTransactionMonthTitleDomId(yearMonth: TextualYearMonth): string {
return 'transaction_month_title_' + yearMonth; return 'transaction_month_title_' + yearMonth;
} }
function getTransactionMonthListDomId(yearMonth: string): string { function getTransactionMonthListDomId(yearMonth: TextualYearMonth): string {
return 'transaction_month_list_' + yearMonth; return 'transaction_month_list_' + yearMonth;
} }
@@ -822,7 +822,7 @@ function getTransactionDomId(transaction: Transaction): string {
} }
function isTransactionMonthListInvisible(transactionMonthList: TransactionMonthList): boolean { function isTransactionMonthListInvisible(transactionMonthList: TransactionMonthList): boolean {
if (!transactionYearMonthListHeights.value[transactionMonthList.yearMonth]) { if (!transactionYearMonthListHeights.value[transactionMonthList.yearDashMonth]) {
return false; return false;
} }
@@ -830,7 +830,7 @@ function isTransactionMonthListInvisible(transactionMonthList: TransactionMonthL
return true; return true;
} }
if (transactionInvisibleYearMonths.value[transactionMonthList.yearMonth]) { if (transactionInvisibleYearMonths.value[transactionMonthList.yearDashMonth]) {
return true; return true;
} }
@@ -839,7 +839,7 @@ function isTransactionMonthListInvisible(transactionMonthList: TransactionMonthL
function getTransactionMonthListHeight(transactionMonthList: TransactionMonthList): string { function getTransactionMonthListHeight(transactionMonthList: TransactionMonthList): string {
if (isTransactionMonthListInvisible(transactionMonthList)) { if (isTransactionMonthListInvisible(transactionMonthList)) {
return transactionYearMonthListHeights.value[transactionMonthList.yearMonth] + 'px'; return transactionYearMonthListHeights.value[transactionMonthList.yearDashMonth] + 'px';
} }
return 'auto'; return 'auto';
@@ -857,12 +857,12 @@ function setTransactionMonthListHeights(reset: boolean): Promise<unknown> {
for (let i = 0; i < transactions.value.length - 1; i++) { for (let i = 0; i < transactions.value.length - 1; i++) {
const transactionMonthList = transactions.value[i]; const transactionMonthList = transactions.value[i];
const yearMonth = transactionMonthList.yearMonth; const yearDashMonth = transactionMonthList.yearDashMonth;
const domId = getTransactionMonthListDomId(yearMonth); const domId = getTransactionMonthListDomId(yearDashMonth);
const height = heights[domId]; const height = heights[domId];
if (!transactionYearMonthListHeights.value[yearMonth] && isNumber(height)) { if (!transactionYearMonthListHeights.value[yearDashMonth] && isNumber(height)) {
transactionYearMonthListHeights.value[yearMonth] = height; transactionYearMonthListHeights.value[yearDashMonth] = height;
} }
} }
} }
@@ -876,30 +876,30 @@ function setTransactionInvisibleYearMonthList(): void {
for (let i = 0; i < transactions.value.length - 1; i++) { for (let i = 0; i < transactions.value.length - 1; i++) {
const transactionMonthList = transactions.value[i]; const transactionMonthList = transactions.value[i];
const yearMonth = transactionMonthList.yearMonth; const yearDashMonth = transactionMonthList.yearDashMonth;
const titleDomId = getTransactionMonthTitleDomId(yearMonth); const titleDomId = getTransactionMonthTitleDomId(yearDashMonth);
const titleRect = getElementBoundingRect(`#${titleDomId}`); const titleRect = getElementBoundingRect(`#${titleDomId}`);
if (!titleRect) { if (!titleRect) {
continue; continue;
} }
const listHeight = transactionYearMonthListHeights.value[yearMonth] || 0; const listHeight = transactionYearMonthListHeights.value[yearDashMonth] || 0;
const listRectTop = titleRect.top + titleRect.height; const listRectTop = titleRect.top + titleRect.height;
const listRectBottom = listRectTop + listHeight; const listRectBottom = listRectTop + listHeight;
const invisible = listRectTop > 2 * window.innerHeight || listRectBottom < -2 * window.innerHeight; const invisible = listRectTop > 2 * window.innerHeight || listRectBottom < -2 * window.innerHeight;
if (invisible) { if (invisible) {
transactionInvisibleYearMonths.value[yearMonth] = true; transactionInvisibleYearMonths.value[yearDashMonth] = true;
} else { } else {
delete transactionInvisibleYearMonths.value[yearMonth]; delete transactionInvisibleYearMonths.value[yearDashMonth];
} }
} }
} }
function getTransactionDateStyle(transaction: Transaction, previousTransaction: Transaction | null): Record<string, string> { function getTransactionDateStyle(transaction: Transaction, previousTransaction: Transaction | null): Record<string, string> {
if (!previousTransaction || transaction.day !== previousTransaction.day) { if (!previousTransaction || transaction.gregorianCalendarDayOfMonth !== previousTransaction.gregorianCalendarDayOfMonth) {
return {}; return {};
} }
@@ -974,9 +974,9 @@ function reload(done?: () => void): void {
transactionTagsStore.loadAllTags({ force: false }) transactionTagsStore.loadAllTags({ force: false })
]).then(() => { ]).then(() => {
if (queryMonthlyData.value) { if (queryMonthlyData.value) {
const currentMonthMinDate = parseDateFromUnixTime(query.value.minTime); const currentMonthMinDate = parseDateTimeFromUnixTime(query.value.minTime);
const currentYear = getYear(currentMonthMinDate); const currentYear = currentMonthMinDate.getGregorianCalendarYear();
const currentMonth = getMonth(currentMonthMinDate); const currentMonth = currentMonthMinDate.getGregorianCalendarMonth();
return transactionsStore.loadMonthlyAllTransactions({ return transactionsStore.loadMonthlyAllTransactions({
year: currentYear, year: currentYear,
@@ -1159,7 +1159,7 @@ function changeCustomDateFilter(minTime: number, maxTime: number): void {
} }
} }
function changeCustomMonthDateFilter(yearMonth: string): void { function changeCustomMonthDateFilter(yearMonth: Year0BasedMonth): void {
if (!yearMonth) { if (!yearMonth) {
return; return;
} }
@@ -1466,8 +1466,8 @@ function collapseTransactionMonthList(monthList: TransactionMonthList, collapse:
collapse: collapse collapse: collapse
}); });
if (!collapse && transactionInvisibleYearMonths.value[monthList.yearMonth]) { if (!collapse && transactionInvisibleYearMonths.value[monthList.yearDashMonth]) {
delete transactionInvisibleYearMonths.value[monthList.yearMonth]; delete transactionInvisibleYearMonths.value[monthList.yearDashMonth];
} }
} }