diff --git a/src/components/base/AccountBalanceTrendsChartBase.ts b/src/components/base/AccountBalanceTrendsChartBase.ts index d0f67dde..82453cc0 100644 --- a/src/components/base/AccountBalanceTrendsChartBase.ts +++ b/src/components/base/AccountBalanceTrendsChartBase.ts @@ -17,7 +17,7 @@ import type { TransactionReconciliationStatementResponseItem } from '@/models/tr import { isDefined, isArray } from '@/lib/common.ts'; import { sumAmounts } from '@/lib/numeral.ts'; import { - getYearAndMonthFromUnixTime, + getGregorianCalendarYearAndMonthFromUnixTime, getYearFirstUnixTimeBySpecifiedUnixTime, getQuarterFirstUnixTimeBySpecifiedUnixTime, getMonthFirstUnixTimeBySpecifiedUnixTime, @@ -99,8 +99,8 @@ export function useAccountBalanceTrendsChartBase(props: CommonAccountBalanceTren if (!isDefined(props.dateAggregationType)) { return getAllDaysStartAndEndUnixTimes(dataDateRange.value.minUnixTime, dataDateRange.value.maxUnixTime); } else { - const startYearMonth = getYearAndMonthFromUnixTime(dataDateRange.value.minUnixTime); - const endYearMonth = getYearAndMonthFromUnixTime(dataDateRange.value.maxUnixTime); + const startYearMonth = getGregorianCalendarYearAndMonthFromUnixTime(dataDateRange.value.minUnixTime); + const endYearMonth = getGregorianCalendarYearAndMonthFromUnixTime(dataDateRange.value.maxUnixTime); return getAllDateRangesByYearMonthRange(startYearMonth, endYearMonth, props.fiscalYearStart, props.dateAggregationType); } }); diff --git a/src/components/base/DateRangeSelectionBase.ts b/src/components/base/DateRangeSelectionBase.ts index d891d12a..cf4affca 100644 --- a/src/components/base/DateRangeSelectionBase.ts +++ b/src/components/base/DateRangeSelectionBase.ts @@ -4,9 +4,9 @@ import { type TimeRangeAndDateType, type PresetDateRange, type UnixTimeRange, ty import { arrangeArrayWithNewStartIndex } from '@/lib/common.ts'; import { getCurrentUnixTime, - getCurrentYear, - getUnixTime, + getAllowedYearRange, getLocalDatetimeFromUnixTime, + getUnixTimeFromLocalDatetime, getTodayFirstUnixTime, getDummyUnixTimeForLocalUsage, getActualUnixTimeForStore, @@ -50,10 +50,7 @@ export function useDateRangeSelectionBase(props: CommonDateRangeSelectionProps) const userStore = useUserStore(); const { minDate, maxDate } = getDateRangeFromProps(props); - const yearRange = ref([ - 2000, - getCurrentYear() + 1 - ]); + const yearRange = ref(getAllowedYearRange()); const dateRange = ref([ getLocalDatetimeFromUnixTime(getDummyUnixTimeForLocalUsage(minDate, getTimezoneOffsetMinutes(), getBrowserTimezoneOffsetMinutes())), @@ -65,11 +62,11 @@ export function useDateRangeSelectionBase(props: CommonDateRangeSelectionProps) const isYearFirst = computed(() => isLongDateMonthAfterYear()); const is24Hour = computed(() => isLongTime24HourFormat()); const beginDateTime = computed(() => { - const actualBeginUnixTime = getActualUnixTimeForStore(getUnixTime(dateRange.value[0]), getTimezoneOffsetMinutes(), getBrowserTimezoneOffsetMinutes()); + const actualBeginUnixTime = getActualUnixTimeForStore(getUnixTimeFromLocalDatetime(dateRange.value[0]), getTimezoneOffsetMinutes(), getBrowserTimezoneOffsetMinutes()); return formatUnixTimeToLongDateTime(actualBeginUnixTime); }); const endDateTime = computed(() => { - const actualEndUnixTime = getActualUnixTimeForStore(getUnixTime(dateRange.value[1]), getTimezoneOffsetMinutes(), getBrowserTimezoneOffsetMinutes()); + const actualEndUnixTime = getActualUnixTimeForStore(getUnixTimeFromLocalDatetime(dateRange.value[1]), getTimezoneOffsetMinutes(), getBrowserTimezoneOffsetMinutes()); return formatUnixTimeToLongDateTime(actualEndUnixTime); }); const presetRanges = computed(() => { @@ -108,8 +105,8 @@ export function useDateRangeSelectionBase(props: CommonDateRangeSelectionProps) const currentMinDate = dateRange.value[0]; const currentMaxDate = dateRange.value[1]; - let minUnixTime = getUnixTime(currentMinDate); - let maxUnixTime = getUnixTime(currentMaxDate); + let minUnixTime = getUnixTimeFromLocalDatetime(currentMinDate); + let maxUnixTime = getUnixTimeFromLocalDatetime(currentMaxDate); if (minUnixTime < 0 || maxUnixTime < 0) { throw new Error('Date is too early'); diff --git a/src/components/base/DateTimeSelectionBase.ts b/src/components/base/DateTimeSelectionBase.ts index eaa1b904..c17d868e 100644 --- a/src/components/base/DateTimeSelectionBase.ts +++ b/src/components/base/DateTimeSelectionBase.ts @@ -7,7 +7,7 @@ import { useUserStore } from '@/stores/user.ts'; import { type NameValue } from '@/core/base.ts'; import { type WeekDayValue } from '@/core/datetime.ts'; import { arrangeArrayWithNewStartIndex } from '@/lib/common.ts'; -import { getCurrentYear } from '@/lib/datetime.ts'; +import { getAllowedYearRange } from '@/lib/datetime.ts'; export interface TimePickerValue { value: string; @@ -34,10 +34,7 @@ export function useDateTimeSelectionBase() { const isSecondTwoDigits = ref(isLongTimeSecondTwoDigits()); const isMeridiemIndicatorFirst = ref(isLongTimeMeridiemIndicatorFirst() || false); - const yearRange = ref([ - 2000, - getCurrentYear() + 1 - ]); + const yearRange = ref(getAllowedYearRange()); const meridiemItems = computed(() => getAllMeridiemIndicators()); diff --git a/src/components/base/FiscalYearStartSelectionBase.ts b/src/components/base/FiscalYearStartSelectionBase.ts index 4906fa0a..3d1cc2f3 100644 --- a/src/components/base/FiscalYearStartSelectionBase.ts +++ b/src/components/base/FiscalYearStartSelectionBase.ts @@ -41,7 +41,7 @@ function getFiscalYearStartFromProps(props: CommonFiscalYearStartSelectionProps) export function useFiscalYearStartSelectionBase(props: CommonFiscalYearStartSelectionProps) { const { getAllMinWeekdayNames, - formatMonthDayToLongDay + formatGregorianCalendarMonthDashDayToLongMonthDay } = useI18n(); const userStore = useUserStore(); @@ -81,7 +81,7 @@ export function useFiscalYearStartSelectionBase(props: CommonFiscalYearStartSele fiscalYearStart = FiscalYearStart.Default; } - return formatMonthDayToLongDay(fiscalYearStart.toMonthDashDayString()); + return formatGregorianCalendarMonthDashDayToLongMonthDay(fiscalYearStart.toMonthDashDayString()); }); const allowedMinDate = computed(() => getLocalDatetimeFromUnixTime(getThisYearFirstUnixTime())); diff --git a/src/components/base/MonthRangeSelectionBase.ts b/src/components/base/MonthRangeSelectionBase.ts index 1fe06beb..aa62add9 100644 --- a/src/components/base/MonthRangeSelectionBase.ts +++ b/src/components/base/MonthRangeSelectionBase.ts @@ -1,13 +1,13 @@ import { ref, computed } from 'vue'; -import type { Year0BasedMonth } from '@/core/datetime.ts'; +import type { TextualYearMonth, Year0BasedMonth } from '@/core/datetime.ts'; import { getYear0BasedMonthObjectFromUnixTime, getYear0BasedMonthObjectFromString, getYearMonthStringFromYear0BasedMonthObject, getCurrentUnixTime, - getCurrentYear, + getAllowedYearRange, getThisYearFirstUnixTime, getYearMonthFirstUnixTime, getYearMonthLastUnixTime @@ -21,8 +21,8 @@ export interface MonthSelectionValue { } export interface CommonMonthRangeSelectionProps { - minTime?: string; - maxTime?: string; + minTime?: TextualYearMonth; + maxTime?: TextualYearMonth; title?: string; hint?: string; show: boolean; @@ -64,11 +64,7 @@ export function useMonthRangeSelectionBase(props: CommonMonthRangeSelectionProps const { formatUnixTimeToLongYearMonth, isLongDateMonthAfterYear } = useI18n(); const { minDate, maxDate } = getMonthRangeFromProps(props); - const yearRange = ref([ - 2000, - getCurrentYear() + 1 - ]); - + const yearRange = ref(getAllowedYearRange()); const dateRange = ref([ minDate, maxDate @@ -84,7 +80,7 @@ export function useMonthRangeSelectionBase(props: CommonMonthRangeSelectionProps month0base: dateRange.value[1].month }))); - function getMonthSelectionValue(yearMonth: string): MonthSelectionValue | null { + function getMonthSelectionValue(yearMonth: TextualYearMonth): MonthSelectionValue | null { const yearMonthObj = getYear0BasedMonthObjectFromString(yearMonth); 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]) { return null; } diff --git a/src/components/base/MonthSelectionBase.ts b/src/components/base/MonthSelectionBase.ts index 6163c2fa..a81a697b 100644 --- a/src/components/base/MonthSelectionBase.ts +++ b/src/components/base/MonthSelectionBase.ts @@ -4,9 +4,7 @@ import type { Year0BasedMonth } from '@/core/datetime.ts'; import { getYear0BasedMonthObjectFromUnixTime, - getYear0BasedMonthObjectFromString, - getYearMonthStringFromYear0BasedMonthObject, - getCurrentYear, + getAllowedYearRange, getThisMonthFirstUnixTime } from '@/lib/datetime.ts'; @@ -18,7 +16,7 @@ export interface MonthSelectionValue { } export interface CommonMonthSelectionProps { - modelValue?: string; + modelValue?: Year0BasedMonth; title?: string; hint?: string; show: boolean; @@ -28,11 +26,7 @@ function getYearMonthValueFromProps(props: CommonMonthSelectionProps): MonthSele let value: Year0BasedMonth = getYear0BasedMonthObjectFromUnixTime(getThisMonthFirstUnixTime()); if (props.modelValue) { - const yearMonth = getYear0BasedMonthObjectFromString(props.modelValue); - - if (yearMonth) { - value = yearMonth; - } + value = props.modelValue; } return { @@ -44,29 +38,23 @@ function getYearMonthValueFromProps(props: CommonMonthSelectionProps): MonthSele export function useMonthSelectionBase(props: CommonMonthSelectionProps) { const { isLongDateMonthAfterYear } = useI18n(); - const yearRange = ref([ - 2000, - getCurrentYear() + 1 - ]); - + const yearRange = ref(getAllowedYearRange()); const monthValue = ref(getYearMonthValueFromProps(props)); const isYearFirst = computed(() => isLongDateMonthAfterYear()); - function getMonthSelectionValue(yearMonth: string): MonthSelectionValue | null { - const yearMonthObj = getYear0BasedMonthObjectFromString(yearMonth); - - if (!yearMonthObj) { + function getMonthSelectionValue(yearMonth: Year0BasedMonth): MonthSelectionValue | null { + if (!yearMonth) { return null; } return { - year: yearMonthObj.year, - month: yearMonthObj.month0base + year: yearMonth.year, + month: yearMonth.month0base }; } - function getTextualYearMonth(): string | null { + function getYear0BasedMonth(): Year0BasedMonth | null { if (!monthValue.value) { return null; } @@ -75,10 +63,10 @@ export function useMonthSelectionBase(props: CommonMonthSelectionProps) { throw new Error('Date is too early'); } - return getYearMonthStringFromYear0BasedMonthObject({ + return { year: monthValue.value.year, month0base: monthValue.value.month - }); + }; } return { @@ -89,6 +77,6 @@ export function useMonthSelectionBase(props: CommonMonthSelectionProps) { isYearFirst, // functions getMonthSelectionValue, - getTextualYearMonth + getYear0BasedMonth }; } diff --git a/src/components/base/MonthlyTrendsChartBase.ts b/src/components/base/MonthlyTrendsChartBase.ts index 8e641dbf..cdb4bb9a 100644 --- a/src/components/base/MonthlyTrendsChartBase.ts +++ b/src/components/base/MonthlyTrendsChartBase.ts @@ -3,6 +3,7 @@ import { computed } from 'vue'; import { useI18n } from '@/locales/helpers.ts'; import type { + TextualYearMonth, Year1BasedMonth, TimeRangeAndDateType, YearUnixTime, @@ -18,8 +19,8 @@ import { getAllDateRangesFromItems } from '@/lib/statistics.ts'; export interface CommonMonthlyTrendsChartProps { items: YearMonthItems[]; - startYearMonth: string; - endYearMonth: string; + startYearMonth: TextualYearMonth | ''; + endYearMonth: TextualYearMonth | ''; fiscalYearStart: number; sortingType: number; dateAggregationType: number; diff --git a/src/components/desktop/DateSelect.vue b/src/components/desktop/DateSelect.vue index be15e732..2b4466c7 100644 --- a/src/components/desktop/DateSelect.vue +++ b/src/components/desktop/DateSelect.vue @@ -44,13 +44,13 @@ import { useI18n } from '@/locales/helpers.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 { arrangeArrayWithNewStartIndex } from '@/lib/common.ts'; -import { getCurrentYear } from '@/lib/datetime.ts'; +import { getAllowedYearRange } from '@/lib/datetime.ts'; const props = defineProps<{ - modelValue?: string; + modelValue?: TextualYearMonthDay; disabled?: boolean; readonly?: boolean; clearable?: boolean; @@ -59,22 +59,19 @@ const props = defineProps<{ }>(); const emit = defineEmits<{ - (e: 'update:modelValue', value: string): void; + (e: 'update:modelValue', value: TextualYearMonthDay): void; }>(); const theme = useTheme(); -const { tt, getAllMinWeekdayNames, getMonthShortName, formatDateToLongDate, isLongDateMonthAfterYear } = useI18n(); +const { tt, getAllMinWeekdayNames, getMonthShortName, formatGregorianCalendarYearDashMonthDashDayToLongDate, isLongDateMonthAfterYear } = useI18n(); const userStore = useUserStore(); -const yearRange = ref([ - 2000, - getCurrentYear() + 1 -]); +const yearRange = ref(getAllowedYearRange()); const dateTime = computed({ get: () => props.modelValue ?? '', - set: (value: string) => emit('update:modelValue', value) + set: (value: string) => emit('update:modelValue', value as TextualYearMonthDay) }); const isDarkMode = computed(() => theme.global.name.value === ThemeType.Dark); @@ -83,7 +80,7 @@ const dayNames = computed(() => arrangeArrayWithNewStartIndex(getAllMi const isYearFirst = computed(() => isLongDateMonthAfterYear()); const displayTime = computed(() => { if (props.modelValue) { - return formatDateToLongDate(props.modelValue); + return formatGregorianCalendarYearDashMonthDashDayToLongDate(props.modelValue); } else if (props.noDataText) { return props.noDataText; } else { diff --git a/src/components/desktop/DateTimeSelect.vue b/src/components/desktop/DateTimeSelect.vue index 72ec1de9..a3b0fc3f 100644 --- a/src/components/desktop/DateTimeSelect.vue +++ b/src/components/desktop/DateTimeSelect.vue @@ -105,7 +105,7 @@ import { getBrowserTimezoneOffsetMinutes, getLocalDatetimeFromUnixTime, getActualUnixTimeForStore, - getUnixTime, + getUnixTimeFromLocalDatetime, getAMOrPM, getCombinedDateAndTimeValues } from '@/lib/datetime.ts'; @@ -154,7 +154,7 @@ const dateTime = computed({ return getLocalDatetimeFromUnixTime(props.modelValue); }, set: (value: Date) => { - const unixTime = getUnixTime(value); + const unixTime = getUnixTimeFromLocalDatetime(value); if (unixTime < 0) { emit('error', 'Date is too early'); @@ -225,7 +225,7 @@ const currentSecond = computed({ }); const isDarkMode = computed(() => theme.global.name.value === ThemeType.Dark); -const displayTime = computed(() => formatUnixTimeToLongDateTime(getActualUnixTimeForStore(getUnixTime(dateTime.value), getTimezoneOffsetMinutes(), getBrowserTimezoneOffsetMinutes()))); +const displayTime = computed(() => formatUnixTimeToLongDateTime(getActualUnixTimeForStore(getUnixTimeFromLocalDatetime(dateTime.value), getTimezoneOffsetMinutes(), getBrowserTimezoneOffsetMinutes()))); function toggleMeridiemIndicator(): void { if (currentMeridiemIndicator.value === MeridiemIndicator.AM.name) { diff --git a/src/components/desktop/MonthRangeSelectionDialog.vue b/src/components/desktop/MonthRangeSelectionDialog.vue index f32bd4f7..4f27086d 100644 --- a/src/components/desktop/MonthRangeSelectionDialog.vue +++ b/src/components/desktop/MonthRangeSelectionDialog.vue @@ -71,6 +71,7 @@ import { useI18n } from '@/locales/helpers.ts'; import { type CommonMonthRangeSelectionProps, useMonthRangeSelectionBase } from '@/components/base/MonthRangeSelectionBase.ts'; import { ThemeType } from '@/core/theme.ts'; +import { type TextualYearMonth } from '@/core/datetime.ts'; interface DesktopMonthRangeSelectionProps extends CommonMonthRangeSelectionProps { persistent?: boolean; @@ -79,7 +80,7 @@ interface DesktopMonthRangeSelectionProps extends CommonMonthRangeSelectionProps const props = defineProps(); const emit = defineEmits<{ (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; }>(); diff --git a/src/components/desktop/MonthSelectionDialog.vue b/src/components/desktop/MonthSelectionDialog.vue index 9dfdfbe7..298fa889 100644 --- a/src/components/desktop/MonthSelectionDialog.vue +++ b/src/components/desktop/MonthSelectionDialog.vue @@ -50,6 +50,7 @@ import { useI18n } from '@/locales/helpers.ts'; import { type CommonMonthSelectionProps, useMonthSelectionBase } from '@/components/base/MonthSelectionBase.ts'; import { ThemeType } from '@/core/theme.ts'; +import type { Year0BasedMonth } from '@/core/datetime.ts'; interface DesktopMonthSelectionProps extends CommonMonthSelectionProps { persistent?: boolean; @@ -57,7 +58,7 @@ interface DesktopMonthSelectionProps extends CommonMonthSelectionProps { const props = defineProps(); const emit = defineEmits<{ - (e: 'update:modelValue', value: string): void; + (e: 'update:modelValue', value: Year0BasedMonth): void; (e: 'update:show', value: boolean): void; (e: 'error', message: string): void; }>(); @@ -65,7 +66,7 @@ const emit = defineEmits<{ const theme = useTheme(); const { tt, getMonthShortName } = useI18n(); -const { yearRange, monthValue, isYearFirst, getMonthSelectionValue, getTextualYearMonth } = useMonthSelectionBase(props); +const { yearRange, monthValue, isYearFirst, getMonthSelectionValue, getYear0BasedMonth } = useMonthSelectionBase(props); const isDarkMode = computed(() => theme.global.name.value === ThemeType.Dark); const showState = computed({ @@ -75,7 +76,7 @@ const showState = computed({ function confirm(): void { try { - const finalMonthRange = getTextualYearMonth(); + const finalMonthRange = getYear0BasedMonth(); if (!finalMonthRange) { return; diff --git a/src/components/mobile/DateSelectionSheet.vue b/src/components/mobile/DateSelectionSheet.vue index 4be21bde..bc3e6e26 100644 --- a/src/components/mobile/DateSelectionSheet.vue +++ b/src/components/mobile/DateSelectionSheet.vue @@ -45,17 +45,17 @@ import { useI18n } from '@/locales/helpers.ts'; import { useEnvironmentsStore } from '@/stores/environment.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 { getCurrentYear } from '@/lib/datetime.ts'; +import { getAllowedYearRange } from '@/lib/datetime.ts'; const props = defineProps<{ - modelValue?: string; + modelValue?: TextualYearMonthDay; show: boolean; }>(); const emit = defineEmits<{ - (e: 'update:modelValue', value: string): void; + (e: 'update:modelValue', value: TextualYearMonthDay): void; (e: 'update:show', value: boolean): void; }>(); @@ -64,10 +64,7 @@ const { tt, getAllMinWeekdayNames, getMonthShortName, isLongDateMonthAfterYear } const environmentsStore = useEnvironmentsStore(); const userStore = useUserStore(); -const yearRange = ref([ - 2000, - getCurrentYear() + 1 -]); +const yearRange = ref(getAllowedYearRange()); const dateTime = ref(''); const isDarkMode = computed(() => environmentsStore.framework7DarkMode || false); @@ -81,7 +78,7 @@ function clear(): void { } function confirm(): void { - emit('update:modelValue', dateTime.value); + emit('update:modelValue', dateTime.value as TextualYearMonthDay); emit('update:show', false); } diff --git a/src/components/mobile/DateTimeSelectionSheet.vue b/src/components/mobile/DateTimeSelectionSheet.vue index 6c81ed40..dfea8c60 100644 --- a/src/components/mobile/DateTimeSelectionSheet.vue +++ b/src/components/mobile/DateTimeSelectionSheet.vue @@ -132,7 +132,7 @@ import { getLocalDatetimeFromUnixTime, getActualUnixTimeForStore, getCurrentUnixTime, - getUnixTime, + getUnixTimeFromLocalDatetime, getAMOrPM, getCombinedDateAndTimeValues } from '@/lib/datetime.ts'; @@ -225,7 +225,7 @@ const currentSecond = computed({ }); const isDarkMode = computed(() => environmentsStore.framework7DarkMode || false); -const displayTime = computed(() => formatUnixTimeToLongDateTime(getActualUnixTimeForStore(getUnixTime(dateTime.value), getTimezoneOffsetMinutes(), getBrowserTimezoneOffsetMinutes()))); +const displayTime = computed(() => formatUnixTimeToLongDateTime(getActualUnixTimeForStore(getUnixTimeFromLocalDatetime(dateTime.value), getTimezoneOffsetMinutes(), getBrowserTimezoneOffsetMinutes()))); const switchButtonTitle = computed(() => mode.value === 'time' ? 'Date' : 'Time'); function switchMode(): void { @@ -249,7 +249,7 @@ function confirm(): void { return; } - const unixTime = getUnixTime(dateTime.value); + const unixTime = getUnixTimeFromLocalDatetime(dateTime.value); if (unixTime < 0) { showToast('Date is too early'); diff --git a/src/components/mobile/MonthRangeSelectionSheet.vue b/src/components/mobile/MonthRangeSelectionSheet.vue index 81920145..a2a8001d 100644 --- a/src/components/mobile/MonthRangeSelectionSheet.vue +++ b/src/components/mobile/MonthRangeSelectionSheet.vue @@ -52,10 +52,12 @@ import { type CommonMonthRangeSelectionProps, useMonthRangeSelectionBase } from import { useEnvironmentsStore } from '@/stores/environment.ts'; +import { type TextualYearMonth } from '@/core/datetime.ts'; + const props = defineProps(); const emit = defineEmits<{ (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(); diff --git a/src/components/mobile/MonthSelectionSheet.vue b/src/components/mobile/MonthSelectionSheet.vue index b9a22588..d30d2a40 100644 --- a/src/components/mobile/MonthSelectionSheet.vue +++ b/src/components/mobile/MonthSelectionSheet.vue @@ -44,17 +44,18 @@ import { useI18n } from '@/locales/helpers.ts'; import { useI18nUIComponents } from '@/lib/ui/mobile.ts'; import { type CommonMonthSelectionProps, useMonthSelectionBase } from '@/components/base/MonthSelectionBase.ts'; +import type { Year0BasedMonth } from '@/core/datetime.ts'; import { useEnvironmentsStore } from '@/stores/environment.ts'; const props = defineProps(); const emit = defineEmits<{ - (e: 'update:modelValue', value: string): void; + (e: 'update:modelValue', value: Year0BasedMonth): void; (e: 'update:show', value: boolean): void; }>(); const { tt, getMonthShortName } = useI18n(); const { showToast } = useI18nUIComponents(); -const { yearRange, monthValue, isYearFirst, getMonthSelectionValue, getTextualYearMonth } = useMonthSelectionBase(props); +const { yearRange, monthValue, isYearFirst, getMonthSelectionValue, getYear0BasedMonth } = useMonthSelectionBase(props); const environmentsStore = useEnvironmentsStore(); @@ -62,7 +63,7 @@ const isDarkMode = computed(() => environmentsStore.framework7DarkMode function confirm(): void { try { - const finalMonthRange = getTextualYearMonth(); + const finalMonthRange = getYear0BasedMonth(); if (!finalMonthRange) { return; diff --git a/src/core/datetime.ts b/src/core/datetime.ts index 53b8996b..ff1864fc 100644 --- a/src/core/datetime.ts +++ b/src/core/datetime.ts @@ -1,5 +1,27 @@ 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 { readonly year: number; readonly quarter: number; diff --git a/src/core/fiscalyear.ts b/src/core/fiscalyear.ts index 2f4e871d..908e6f69 100644 --- a/src/core/fiscalyear.ts +++ b/src/core/fiscalyear.ts @@ -1,4 +1,4 @@ -import type { UnixTimeRange } from './datetime.ts'; +import type { TextualYearMonth, UnixTimeRange } from './datetime.ts'; export class FiscalYearStart { public static readonly JanuaryFirstDay = new FiscalYearStart(1, 1); @@ -75,8 +75,8 @@ export class FiscalYearStart { return FiscalYearStart.of(month, day); } - public toMonthDashDayString(): string { - return `${this.month.toString().padStart(2, '0')}-${this.day.toString().padStart(2, '0')}`; + public toMonthDashDayString(): TextualYearMonth { + return `${this.month.toString().padStart(2, '0')}-${this.day.toString().padStart(2, '0')}` as TextualYearMonth; } private static isValidFiscalYearMonthDay(month: number, day: number): boolean { diff --git a/src/lib/__tests__/fiscal_year.ts b/src/lib/__tests__/fiscal_year.ts index 9189c6c1..f017da7b 100644 --- a/src/lib/__tests__/fiscal_year.ts +++ b/src/lib/__tests__/fiscal_year.ts @@ -5,6 +5,7 @@ import { describe, expect, test, beforeAll } from '@jest/globals'; import moment from 'moment-timezone'; // Import all the fiscal year functions from the lib +import type { TextualYearMonth } from '@/core/datetime.ts'; import { FiscalYearStart, FiscalYearUnixTime } from '@/core/fiscalyear.ts'; import { @@ -230,8 +231,8 @@ describe('getFiscalYearTimeRangeFromUnixTime', () => { // GET ALL FISCAL YEAR START AND END UNIX TIMES type TestCase_getAllFiscalYearsStartAndEndUnixTimes = { - startYearMonth: string; - endYearMonth: string; + startYearMonth: TextualYearMonth; + endYearMonth: TextualYearMonth; fiscalYearStart: string; fiscalYearStartId: string; expected: FiscalYearUnixTime[] diff --git a/src/lib/datetime.ts b/src/lib/datetime.ts index aed3aa4c..8bd225ab 100644 --- a/src/lib/datetime.ts +++ b/src/lib/datetime.ts @@ -2,11 +2,15 @@ import moment from 'moment-timezone'; import { type unitOfTime } from 'moment/moment'; import { + type DateTime, + type TextualYearMonth, + type TextualYearMonthDay, type YearUnixTime, type YearQuarter, type Year0BasedMonth, type Year1BasedMonth, type YearMonthRange, + type YearMonthDay, type TimeRange, type TimeRangeAndDateType, type TimeDifference, @@ -35,7 +39,120 @@ import { isNumber } 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 { 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)) { 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)) { return ''; } - return `${yearMonth.year}-${yearMonth.month0base + 1}`; + return (`${yearMonth.year}-${yearMonth.month0base + 1}`) as TextualYearMonth; } 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 offsetMinutes = Math.abs(utcOffsetMinutes) - offsetHours * 60; - let finalOffsetHours = offsetHours.toString(); - let finalOffsetMinutes = offsetMinutes.toString(); - - if (offsetHours < 10) { - finalOffsetHours = '0' + offsetHours; - } - - if (offsetMinutes < 10) { - finalOffsetMinutes = '0' + offsetMinutes; - } + const finalOffsetHours = offsetHours.toString().padStart(2, '0'); + const finalOffsetMinutes = offsetMinutes.toString().padStart(2, '0'); if (utcOffsetMinutes >= 0) { return `+${finalOffsetHours}:${finalOffsetMinutes}`; @@ -180,23 +289,15 @@ export function getDummyUnixTimeForLocalUsage(unixTime: number, utcOffset: numbe return unixTime + (utcOffset - currentUtcOffset) * 60; } +export function getCurrentDateTime(): DateTime { + return MomentDateTime.now(); +} + export function getCurrentUnixTime(): number { return moment().unix(); } -export function getCurrentYear(): number { - 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 { +export function parseDateTimeFromUnixTime(unixTime: number, utcOffset?: number, currentUtcOffset?: number): DateTime { if (isNumber(utcOffset)) { if (!isNumber(currentUtcOffset)) { currentUtcOffset = getTimezoneOffsetMinutes(); @@ -205,73 +306,31 @@ export function parseDateFromUnixTime(unixTime: number, utcOffset?: number, curr 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) { - return parseDateFromUnixTime(unixTime, utcOffset, currentUtcOffset).format(format); +export function formatUnixTime(unixTime: number, format: string, utcOffset?: number, currentUtcOffset?: number): string { + return parseDateTimeFromUnixTime(unixTime, utcOffset, currentUtcOffset).format(format); } export function formatCurrentTime(format: string): string { 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); } -export function formatMonthDay(monthDay: string, format: string): string { +export function formatGregorianCalendarMonthDashDay(monthDay: TextualYearMonth, format: string): string { return moment(monthDay, 'MM-DD').format(format); } -export function getUnixTime(date: SupportedDate): number { - 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 { +export function getGregorianCalendarYearAndMonthFromUnixTime(unixTime: number): TextualYearMonth | '' { if (!unixTime) { return ''; } - return getYearAndMonth(parseDateFromUnixTime(unixTime)); -} - -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; + return parseDateTimeFromUnixTime(unixTime).getGregorianCalendarYearDashMonth(); } 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 { 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(); } -export function getYearMonthFirstUnixTime(yearMonth: Year0BasedMonth | Year1BasedMonth | string): number { +export function getYearMonthFirstUnixTime(yearMonth: Year0BasedMonth | Year1BasedMonth | TextualYearMonth | ''): number { let yearMonthObj: Year0BasedMonth | null = null; 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(); } -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(); } -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 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 range = getStartEndYearMonthRange(startYearMonth, endYearMonth); @@ -494,7 +544,7 @@ export function getAllYearsStartAndEndUnixTimes(startYearMonth: Year0BasedMonth 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 // 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 @@ -544,7 +594,7 @@ export function getAllFiscalYearsStartAndEndUnixTimes(startYearMonth: Year0Based 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 range = getStartEndYearMonthRange(startYearMonth, endYearMonth); @@ -578,7 +628,7 @@ export function getAllQuartersStartAndEndUnixTimes(startYearMonth: Year0BasedMon 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 range = getStartEndYearMonthRange(startYearMonth, endYearMonth); @@ -622,16 +672,11 @@ export function getAllDaysStartAndEndUnixTimes(startUnixTime: number, endUnixTim let unixTime: number = startUnixTime; while (unixTime <= endUnixTime) { - const currentDay = parseDateFromUnixTime(unixTime); + const currentDateTime = parseDateTimeFromUnixTime(unixTime); const currentDayMinUnixTime = getDayFirstUnixTimeBySpecifiedUnixTime(unixTime); const currentDayMaxUnixTime = getDayLastUnixTimeBySpecifiedUnixTime(unixTime); - allYearMonthDayTimes.push(YearMonthDayUnixTime.of({ - year: currentDay.year(), - month: currentDay.month() + 1, - day: currentDay.date() - }, currentDayMinUnixTime, currentDayMaxUnixTime)); - + allYearMonthDayTimes.push(YearMonthDayUnixTime.of(currentDateTime.toGregorianCalendarYearMonthDay(), currentDayMinUnixTime, currentDayMaxUnixTime)); unixTime = currentDayMaxUnixTime + 1; } @@ -649,15 +694,15 @@ export function getDateTimeFormatType(allForm } export function getShiftedDateRange(minTime: number, maxTime: number, scale: number): TimeRange { - const minDateTime = parseDateFromUnixTime(minTime).set({ millisecond: 0 }); - const maxDateTime = parseDateFromUnixTime(maxTime).set({ millisecond: 999 }); + const minDateTime = moment.unix(parseDateTimeFromUnixTime(minTime).getUnixTime()).set({ millisecond: 0 }); + const maxDateTime = moment.unix(parseDateTimeFromUnixTime(maxTime).getUnixTime()).set({ millisecond: 999 }); const firstDayOfMonth = minDateTime.clone().startOf('month'); const lastDayOfMonth = maxDateTime.clone().endOf('month'); // check whether the date range matches full months 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 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 (statementDate) { - if (getCurrentDay() <= statementDate) { + if (getCurrentDateTime().getGregorianCalendarDay() <= statementDate) { maxTime = getThisMonthSpecifiedDayLastUnixTime(statementDate); minTime = getUnixTimeBeforeUnixTime(getUnixTimeAfterUnixTime(getThisMonthSpecifiedDayFirstUnixTime(statementDate), 1, 'days'), 1, 'months'); } else { @@ -898,8 +943,8 @@ export function getRecentMonthDateRanges(monthCount: number): RecentMonthDateRan const maxTime = getUnixTimeBeforeUnixTime(getUnixTimeAfterUnixTime(minTime, 1, 'months'), 1, 'seconds'); let dateType = DateRange.Custom.type; - const year = getYear(parseDateFromUnixTime(minTime)); - const month = getMonth(parseDateFromUnixTime(minTime)); + const year = parseDateTimeFromUnixTime(minTime).getGregorianCalendarYear(); + const month = parseDateTimeFromUnixTime(minTime).getGregorianCalendarMonth(); if (i === 0) { dateType = DateRange.ThisMonth.type; @@ -1004,7 +1049,7 @@ export function getCombinedDateAndTimeValues(date: Date, hour: string, minute: s return newDateTime; } -export function getValidMonthDayOrCurrentDayShortDate(unixTime: number, currentShortDate: string): string { +export function getValidMonthDayOrCurrentDayShortDate(unixTime: number, currentShortDate: string): TextualYearMonthDay { const currentTime = moment(); const monthLastTime = moment.unix(getMonthLastUnixTimeBySpecifiedUnixTime(unixTime)); @@ -1015,43 +1060,35 @@ export function getValidMonthDayOrCurrentDayShortDate(unixTime: number, currentS const currentDay = parseInt(yearMonthDay[2]); 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()) { - return getShortDate(currentTime); + return MomentDateTime.of(currentTime).getGregorianCalendarYearDashMonthDashDay(); } - return getShortDate(monthLastTime); + return MomentDateTime.of(monthLastTime).getGregorianCalendarYearDashMonthDashDay(); } export function isDateRangeMatchFullYears(minTime: number, maxTime: number): boolean { - const minDateTime = parseDateFromUnixTime(minTime).set({ millisecond: 0 }); - const maxDateTime = parseDateFromUnixTime(maxTime).set({ millisecond: 999 }); - - const firstDayOfYear = minDateTime.clone().startOf('year'); - const lastDayOfYear = maxDateTime.clone().endOf('year'); - - return firstDayOfYear.unix() === minDateTime.unix() && lastDayOfYear.unix() === maxDateTime.unix(); + const minDateTime = parseDateTimeFromUnixTime(minTime); + const maxDateTime = parseDateTimeFromUnixTime(maxTime); + return MomentDateTime.isYearFirstTime(minDateTime as MomentDateTime) && MomentDateTime.isYearLastTime(maxDateTime as MomentDateTime); } export function isDateRangeMatchFullMonths(minTime: number, maxTime: number): boolean { - const minDateTime = parseDateFromUnixTime(minTime).set({ millisecond: 0 }); - const maxDateTime = parseDateFromUnixTime(maxTime).set({ millisecond: 999 }); - - const firstDayOfMonth = minDateTime.clone().startOf('month'); - const lastDayOfMonth = maxDateTime.clone().endOf('month'); - - return firstDayOfMonth.unix() === minDateTime.unix() && lastDayOfMonth.unix() === maxDateTime.unix(); + const minDateTime = parseDateTimeFromUnixTime(minTime); + const maxDateTime = parseDateTimeFromUnixTime(maxTime); + return MomentDateTime.isMonthFirstTime(minDateTime as MomentDateTime) && MomentDateTime.isMonthLastTime(maxDateTime as MomentDateTime); } export function isDateRangeMatchOneMonth(minTime: number, maxTime: number): boolean { - const minDateTime = parseDateFromUnixTime(minTime); - const maxDateTime = parseDateFromUnixTime(maxTime); + const minDateTime = parseDateTimeFromUnixTime(minTime); + const maxDateTime = parseDateTimeFromUnixTime(maxTime); - if (getYear(minDateTime) !== getYear(maxDateTime) || getMonth(minDateTime) !== getMonth(maxDateTime)) { + if (minDateTime.getGregorianCalendarYear() !== maxDateTime.getGregorianCalendarYear() || minDateTime.getGregorianCalendarMonth() !== maxDateTime.getGregorianCalendarMonth()) { return false; } diff --git a/src/lib/statistics.ts b/src/lib/statistics.ts index 8290379c..82b95757 100644 --- a/src/lib/statistics.ts +++ b/src/lib/statistics.ts @@ -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 { ChartSortingType, ChartDateAggregationType } from '@/core/statistics.ts'; import type { @@ -48,7 +48,7 @@ export function sortStatisticsItems(items: YearMonthItems[], startYearMonth: Year1BasedMonth | string, endYearMonth: Year1BasedMonth | string, fiscalYearStart: number, dateAggregationType: number): YearUnixTime[] | FiscalYearUnixTime[] | YearQuarterUnixTime[] | YearMonthUnixTime[] { +export function getAllDateRangesFromItems(items: YearMonthItems[], startYearMonth: Year1BasedMonth | TextualYearMonth | '', endYearMonth: Year1BasedMonth | TextualYearMonth | '', fiscalYearStart: number, dateAggregationType: number): YearUnixTime[] | FiscalYearUnixTime[] | YearQuarterUnixTime[] | YearMonthUnixTime[] { if ((!startYearMonth || !endYearMonth) && items && items.length) { let minYear = Number.MAX_SAFE_INTEGER, minMonth = Number.MAX_SAFE_INTEGER, maxYear = 0, maxMonth = 0; @@ -70,14 +70,14 @@ export function getAllDateRangesFromItems(items: Year } } - startYearMonth = `${minYear}-${minMonth}`; - endYearMonth = `${maxYear}-${maxMonth}`; + startYearMonth = `${minYear}-${minMonth}` as TextualYearMonth; + endYearMonth = `${maxYear}-${maxMonth}` as TextualYearMonth; } 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) { return []; } diff --git a/src/locales/helpers.ts b/src/locales/helpers.ts index fbea19a3..358810de 100644 --- a/src/locales/helpers.ts +++ b/src/locales/helpers.ts @@ -16,6 +16,8 @@ import { } from '@/core/text.ts'; import { + type TextualYearMonth, + type TextualYearMonthDay, type DateFormat, type TimeFormat, type LocalizedDateTimeFormat, @@ -148,12 +150,13 @@ import { import { formatCurrentTime, - formatDate, - formatMonthDay, + formatGregorianCalendarYearDashMonthDashDay, + formatGregorianCalendarMonthDashDay, formatUnixTime, getBrowserTimezoneOffset, getBrowserTimezoneOffsetMinutes, getCurrentUnixTime, + parseDateTimeFromUnixTime, getDateTimeFormatType, getFiscalYearTimeRangeFromUnixTime, getFiscalYearTimeRangeFromYear, @@ -161,12 +164,9 @@ import { getTimeDifferenceHoursAndMinutes, getTimezoneOffset, getTimezoneOffsetMinutes, - getYear, - getQuarter, isDateRangeMatchFullMonths, isDateRangeMatchFullYears, - isPM, - parseDateFromUnixTime, + isPM } from '@/lib/datetime.ts'; import { @@ -1441,12 +1441,12 @@ export function useI18n() { }); } - function getWeekdayShortName(weekDayName: string): string { - return t(`datetime.${weekDayName}.short`); + function getWeekdayShortName(weekDay: WeekDay): string { + return t(`datetime.${weekDay.name}.short`); } - function getWeekdayLongName(weekDayName: string): string { - return t(`datetime.${weekDayName}.long`); + function getWeekdayLongName(weekDay: WeekDay): string { + return t(`datetime.${weekDay.name}.long`); } function getMultiMonthdayShortNames(monthDays: number[]): string { @@ -1618,18 +1618,18 @@ export function useI18n() { return getLocalizedLongTimeFormat().indexOf('ss') >= 0; } - function formatDateToLongDate(date: string): string { - return formatDate(date, getLocalizedLongDateFormat()); + function formatGregorianCalendarYearDashMonthDashDayToLongDate(date: TextualYearMonthDay): string { + return formatGregorianCalendarYearDashMonthDashDay(date, getLocalizedLongDateFormat()); } - function formatMonthDayToLongDay(monthDay: string): string { - return formatMonthDay(monthDay, getLocalizedLongMonthDayFormat()); + function formatGregorianCalendarMonthDashDayToLongMonthDay(monthDay: TextualYearMonth): string { + return formatGregorianCalendarMonthDashDay(monthDay, getLocalizedLongMonthDayFormat()); } function formatUnixTimeToYearQuarter(unixTime: number): string { - const date = parseDateFromUnixTime(unixTime); - const year = getYear(date); - const quarter = getQuarter(date); + const date = parseDateTimeFromUnixTime(unixTime); + const year = date.getLocalizedCalendarYear(); + const quarter = date.getLocalizedCalendarQuarter(); return formatYearQuarter(year, quarter); } @@ -1675,8 +1675,8 @@ export function useI18n() { return displayStartTime !== displayEndTime ? `${displayStartTime} ~ ${displayEndTime}` : displayStartTime; } - const startTimeYear = getYear(parseDateFromUnixTime(startTime)); - const endTimeYear = getYear(parseDateFromUnixTime(endTime)); + const startTimeYear = parseDateTimeFromUnixTime(startTime).getLocalizedCalendarYear(); + const endTimeYear = parseDateTimeFromUnixTime(endTime).getLocalizedCalendarYear(); const format = getLocalizedShortDateFormat(); const displayStartTime = formatUnixTime(startTime, format); @@ -1734,7 +1734,7 @@ export function useI18n() { fiscalYearStart = FiscalYearStart.Default; } - return formatMonthDayToLongDay(fiscalYearStart.toMonthDashDayString()); + return formatGregorianCalendarMonthDashDayToLongMonthDay(fiscalYearStart.toMonthDashDayString()); } function getTimezoneDifferenceDisplayText(utcOffset: number): string { @@ -2168,8 +2168,8 @@ export function useI18n() { formatUnixTimeToShortMonthDay: (unixTime: number, utcOffset?: number, currentUtcOffset?: number) => formatUnixTime(unixTime, getLocalizedShortMonthDayFormat(), 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), - formatDateToLongDate, - formatMonthDayToLongDay, + formatGregorianCalendarYearDashMonthDashDayToLongDate, + formatGregorianCalendarMonthDashDayToLongMonthDay, formatUnixTimeToYearQuarter, formatYearQuarter, formatDateRange, diff --git a/src/models/transaction.ts b/src/models/transaction.ts index 3f3df713..6be61bdd 100644 --- a/src/models/transaction.ts +++ b/src/models/transaction.ts @@ -1,5 +1,5 @@ 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 { TransactionType } from '@/core/transaction.ts'; @@ -35,9 +35,9 @@ export class Transaction implements TransactionInfoResponse { private _destinationAccount?: Account; // only for displaying transaction private _tags?: TransactionTag[]; // only for displaying transaction - private _date?: string = undefined; // only for displaying transaction in transaction list - private _day?: number = undefined; // only for displaying transaction in transaction list - private _dayOfWeek?: string = undefined; // only for displaying transaction in transaction list + private _gregorianCalendarYearDashMonthDashDay?: TextualYearMonthDay = undefined; // only for displaying transaction in transaction list + private _gregorianCalendarDayOfMonth?: number = 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) { this.id = id; @@ -106,16 +106,16 @@ export class Transaction implements TransactionInfoResponse { return ret; } - public get date(): string | undefined { - return this._date; + public get gregorianCalendarYearDashMonthDashDay(): TextualYearMonthDay | undefined { + return this._gregorianCalendarYearDashMonthDashDay; } - public get day(): number | undefined { - return this._day; + public get gregorianCalendarDayOfMonth(): number | undefined { + return this._gregorianCalendarDayOfMonth; } - public get dayOfWeek(): string | undefined { - return this._dayOfWeek; + public get displayDayOfWeek(): WeekDay | undefined { + return this._displayDayOfWeek; } public getCategoryId(): string { @@ -220,10 +220,10 @@ export class Transaction implements TransactionInfoResponse { this._geoLocation = undefined; } - public setDisplayDate(date: string, day: number, dayOfWeek: string): void { - this._date = date; - this._day = day; - this._dayOfWeek = dayOfWeek; + public setDisplayDate(gregorianCalendarYearDashMonthDashDay: TextualYearMonthDay, gregorianCalendarDayOfMonth: number, displayDayOfWeek: WeekDay): void { + this._gregorianCalendarYearDashMonthDashDay = gregorianCalendarYearDashMonthDashDay; + this._gregorianCalendarDayOfMonth = gregorianCalendarDayOfMonth; + this._displayDayOfWeek = displayDayOfWeek; } public toCreateRequest(clientSessionId: string, actualTime?: number): TransactionCreateRequest { diff --git a/src/models/transaction_template.ts b/src/models/transaction_template.ts index 6db9001e..5de8b2c0 100644 --- a/src/models/transaction_template.ts +++ b/src/models/transaction_template.ts @@ -1,3 +1,4 @@ +import { type TextualYearMonthDay } from '@/core/datetime.ts'; import { TransactionType } from '@/core/transaction.ts'; import { TemplateType } from '@/core/template.ts'; @@ -8,13 +9,13 @@ export class TransactionTemplate extends Transaction implements TransactionTempl public name: string; public scheduledFrequencyType?: number; public scheduledFrequency?: string; - public scheduledStartDate?: string; - public scheduledEndDate?: string; + public scheduledStartDate?: TextualYearMonthDay; + public scheduledEndDate?: TextualYearMonthDay; public scheduledAt?: number; public displayOrder: number; 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); this.templateType = templateType; this.name = name; @@ -211,8 +212,8 @@ export interface TransactionTemplateInfoResponse extends TransactionInfoResponse readonly name: string; readonly scheduledFrequencyType?: number; readonly scheduledFrequency?: string; - readonly scheduledStartDate?: string; - readonly scheduledEndDate?: string; + readonly scheduledStartDate?: TextualYearMonthDay; + readonly scheduledEndDate?: TextualYearMonthDay; readonly scheduledAt?: number; readonly displayOrder: number; readonly hidden: boolean; diff --git a/src/stores/statistics.ts b/src/stores/statistics.ts index 239f7a45..e03e88b3 100644 --- a/src/stores/statistics.ts +++ b/src/stores/statistics.ts @@ -7,7 +7,7 @@ import { useAccountsStore } from './account.ts'; import { useTransactionCategoriesStore } from './transactionCategory.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 { CategoryType } from '@/core/category.ts'; import { TransactionTagFilterType } from '@/core/transaction.ts'; @@ -50,7 +50,7 @@ import { isObjectEmpty, objectFieldToArrayItem } 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 { getFinalCategoryIdsByFilteredCategoryIds } from '@/lib/category.ts'; import { sortStatisticsItems } from '@/lib/statistics.ts'; @@ -118,8 +118,8 @@ export interface TransactionStatisticsPartialFilter { categoricalChartEndTime?: number; trendChartType?: number; trendChartDateType?: number; - trendChartStartYearMonth?: string; - trendChartEndYearMonth?: string; + trendChartStartYearMonth?: TextualYearMonth | ''; + trendChartEndYearMonth?: TextualYearMonth | ''; filterAccountIds?: Record; filterCategoryIds?: Record; tagIds?: string; @@ -136,8 +136,8 @@ export interface TransactionStatisticsFilter extends TransactionStatisticsPartia categoricalChartEndTime: number; trendChartType: number; trendChartDateType: number; - trendChartStartYearMonth: string; - trendChartEndYearMonth: string; + trendChartStartYearMonth: TextualYearMonth | ''; + trendChartEndYearMonth: TextualYearMonth | ''; filterAccountIds: Record; filterCategoryIds: Record; tagIds: string; @@ -800,8 +800,8 @@ export const useStatisticsStore = defineStore('statistics', () => { if (trendChartDateRange) { transactionStatisticsFilter.value.trendChartDateType = trendChartDateRange.dateType; - transactionStatisticsFilter.value.trendChartStartYearMonth = getYearAndMonthFromUnixTime(trendChartDateRange.minTime); - transactionStatisticsFilter.value.trendChartEndYearMonth = getYearAndMonthFromUnixTime(trendChartDateRange.maxTime); + transactionStatisticsFilter.value.trendChartStartYearMonth = getGregorianCalendarYearAndMonthFromUnixTime(trendChartDateRange.minTime); + transactionStatisticsFilter.value.trendChartEndYearMonth = getGregorianCalendarYearAndMonthFromUnixTime(trendChartDateRange.maxTime); } } diff --git a/src/stores/transaction.ts b/src/stores/transaction.ts index d99f2382..ac1e71f0 100644 --- a/src/stores/transaction.ts +++ b/src/stores/transaction.ts @@ -10,7 +10,7 @@ import { useStatisticsStore } from './statistics.ts'; import { useExchangeRatesStore } from './exchangeRates.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 { TransactionType, TransactionTagFilterType } from '@/core/transaction.ts'; import { TRANSACTION_MIN_AMOUNT, TRANSACTION_MAX_AMOUNT } from '@/consts/transaction.ts'; @@ -51,13 +51,7 @@ import { getTimezoneOffsetMinutes, getBrowserTimezoneOffsetMinutes, getActualUnixTimeForStore, - parseDateFromUnixTime, - getShortDate, - getYear, - getMonth, - getYearAndMonth, - getDay, - getDayOfWeekName + parseDateTimeFromUnixTime } from '@/lib/datetime.ts'; import { getAmountWithDecimalNumberCount } from '@/lib/numeral.ts'; import { getCurrencyFraction } from '@/lib/currency.ts'; @@ -101,7 +95,7 @@ export interface TransactionTotalAmount { export interface TransactionMonthList { readonly year: number; readonly month: number; // 1-based (1 = January, 12 = December) - readonly yearMonth: string; + readonly yearDashMonth: TextualYearMonth; opened: boolean; readonly items: Transaction[]; readonly totalAmount: TransactionTotalAmount; @@ -177,10 +171,10 @@ export const useTransactionsStore = defineStore('transactions', () => { const item = transactionPageWrapper.items[i]; fillTransactionObject(item, currentUtcOffset); - const transactionTime = parseDateFromUnixTime(item.time, item.utcOffset, currentUtcOffset); - const transactionYear = getYear(transactionTime); - const transactionMonth = getMonth(transactionTime); - const transactionYearMonth = getYearAndMonth(transactionTime); + const transactionTime = parseDateTimeFromUnixTime(item.time, item.utcOffset, currentUtcOffset); + const transactionYear = transactionTime.getGregorianCalendarYear(); + const transactionMonth = transactionTime.getGregorianCalendarMonth(); + const transactionYearDashMonth = transactionTime.getGregorianCalendarYearDashMonth(); if (i === 0 && transactions.value.length > 0) { const lastMonthList = transactions.value[transactions.value.length - 1]; @@ -216,7 +210,7 @@ export const useTransactionsStore = defineStore('transactions', () => { const monthList: TransactionMonthList = { year: transactionYear, month: transactionMonth, - yearMonth: transactionYearMonth, + yearDashMonth: transactionYearDashMonth, opened: autoExpand, items: [], totalAmount: { @@ -250,9 +244,9 @@ export const useTransactionsStore = defineStore('transactions', () => { function updateTransactionInTransactionList({ transaction, defaultCurrency }: { transaction: Transaction, defaultCurrency: string }): void { const currentUtcOffset = getTimezoneOffsetMinutes(settingsStore.appSettings.timeZone); - const transactionTime = parseDateFromUnixTime(transaction.time, transaction.utcOffset, currentUtcOffset); - const transactionYear = getYear(transactionTime); - const transactionMonth = getMonth(transactionTime); + const transactionTime = parseDateTimeFromUnixTime(transaction.time, transaction.utcOffset, currentUtcOffset); + const transactionYear = transactionTime.getGregorianCalendarYear(); + const transactionMonth = transactionTime.getGregorianCalendarMonth(); for (let i = 0; i < transactions.value.length; i++) { const transactionMonthList = transactions.value[i]; @@ -267,7 +261,7 @@ export const useTransactionsStore = defineStore('transactions', () => { if (transactionYear !== transactionMonthList.year || transactionMonth !== transactionMonthList.month || - transaction.day !== transactionMonthList.items[j].day) { + transaction.gregorianCalendarDayOfMonth !== transactionMonthList.items[j].gregorianCalendarDayOfMonth) { transactionListStateInvalid.value = true; return; } @@ -346,7 +340,7 @@ export const useTransactionsStore = defineStore('transactions', () => { for (let i = 0; i < transactionMonthList.items.length; 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]; if (!dailyTotalAmount) { @@ -450,8 +444,8 @@ export const useTransactionsStore = defineStore('transactions', () => { return; } - const transactionTime = parseDateFromUnixTime(transaction.time, transaction.utcOffset, currentUtcOffset); - transaction.setDisplayDate(getShortDate(transactionTime), getDay(transactionTime), getDayOfWeekName(transactionTime)); + const transactionTime = parseDateTimeFromUnixTime(transaction.time, transaction.utcOffset, currentUtcOffset); + transaction.setDisplayDate(transactionTime.getGregorianCalendarYearDashMonthDashDay(), transactionTime.getGregorianCalendarDay(), transactionTime.getWeekDay()); if (transaction.sourceAccountId) { transaction.setSourceAccount(accountsStore.allAccountsMap[transaction.sourceAccountId]); diff --git a/src/views/base/accounts/ReconciliationStatementPageBase.ts b/src/views/base/accounts/ReconciliationStatementPageBase.ts index 6658dce3..2755c9e4 100644 --- a/src/views/base/accounts/ReconciliationStatementPageBase.ts +++ b/src/views/base/accounts/ReconciliationStatementPageBase.ts @@ -23,9 +23,8 @@ import { replaceAll } from '@/lib/common.ts'; import { getUtcOffsetByUtcOffsetMinutes, getTimezoneOffsetMinutes, - parseDateFromUnixTime, - formatUnixTime, - getUnixTime + parseDateTimeFromUnixTime, + formatUnixTime } from '@/lib/datetime.ts'; export function useReconciliationStatementPageBase() { @@ -132,8 +131,7 @@ export function useReconciliationStatementPageBase() { } function getDisplayDateTime(transaction: TransactionReconciliationStatementResponseItem): string { - const transactionTime = getUnixTime(parseDateFromUnixTime(transaction.time, transaction.utcOffset, currentTimezoneOffsetMinutes.value)); - return formatUnixTimeToLongDateTime(transactionTime); + return formatUnixTimeToLongDateTime(transaction.time, transaction.utcOffset, currentTimezoneOffsetMinutes.value); } function getDisplayDate(transaction: TransactionReconciliationStatementResponseItem): string { @@ -210,7 +208,7 @@ export function useReconciliationStatementPageBase() { const transactions = reconciliationStatements.value?.transactions ?? []; 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); let categoryName = allCategoriesMap.value[transaction.categoryId]?.name || ''; let displayAmount = formatAmountToWesternArabicNumeralsWithoutDigitGrouping(transaction.sourceAmount); diff --git a/src/views/base/transactions/TransactionListPageBase.ts b/src/views/base/transactions/TransactionListPageBase.ts index 3a3bfcd3..54f0a908 100644 --- a/src/views/base/transactions/TransactionListPageBase.ts +++ b/src/views/base/transactions/TransactionListPageBase.ts @@ -10,7 +10,7 @@ import { useTransactionTagsStore } from '@/stores/transactionTag.ts'; import { type TransactionListFilter, type TransactionMonthList, useTransactionsStore } from '@/stores/transaction.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 { TransactionType } from '@/core/transaction.ts'; import { DISPLAY_HIDDEN_AMOUNT, INCOMPLETE_AMOUNT_SUFFIX } from '@/consts/numeral.ts'; @@ -28,14 +28,10 @@ import { getLocalDatetimeFromUnixTime, getActualUnixTimeForStore, getDummyUnixTimeForLocalUsage, - getCurrentYearAndMonth, - parseDateFromUnixTime, - getYearAndMonth, - getYear, - getMonth, + getCurrentDateTime, + parseDateTimeFromUnixTime, getYearMonthFirstUnixTime, - getDay, - getUnixTime, + getUnixTimeFromLocalDatetime, isDateRangeMatchOneMonth } from '@/lib/datetime.ts'; @@ -99,7 +95,7 @@ export function useTransactionListPageBase() { const loading = ref(true); const customMinDatetime = ref(0); const customMaxDatetime = ref(0); - const currentCalendarDate = ref(''); + const currentCalendarDate = ref(''); const currentTimezoneOffsetMinutes = computed(() => getTimezoneOffsetMinutes(settingsStore.appSettings.timeZone)); const firstDayOfWeek = computed(() => userStore.currentUserFirstDayOfWeek); @@ -175,12 +171,12 @@ export function useTransactionListPageBase() { const queryMinTime = computed(() => formatUnixTimeToLongDateTime(query.value.minTime)); const queryMaxTime = computed(() => formatUnixTimeToLongDateTime(query.value.maxTime)); const queryMonthlyData = computed(() => isDateRangeMatchOneMonth(query.value.minTime, query.value.maxTime)); - const queryMonth = computed(() => { + const queryMonth = computed(() => { 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>(() => transactionsStore.allFilterCategoryIds); @@ -248,9 +244,9 @@ export function useTransactionListPageBase() { return null; } - const currentMonthMinDate = parseDateFromUnixTime(query.value.minTime); - const currentYear = getYear(currentMonthMinDate); - const currentMonth = getMonth(currentMonthMinDate); + const currentMonthMinDate = parseDateTimeFromUnixTime(query.value.minTime); + const currentYear = currentMonthMinDate.getGregorianCalendarYear(); + const currentMonth = currentMonthMinDate.getGregorianCalendarMonth(); for (let i = 0; i < allTransactions.length; i++) { if (allTransactions[i].year === currentYear && allTransactions[i].month === currentMonth) { @@ -262,8 +258,8 @@ export function useTransactionListPageBase() { }); function noTransactionInMonthDay(date: Date): boolean { - const dateTime = parseDateFromUnixTime(getActualUnixTimeForStore(getUnixTime(date), getTimezoneOffsetMinutes(), getBrowserTimezoneOffsetMinutes())); - return !currentMonthTransactionData.value || !currentMonthTransactionData.value.dailyTotalAmounts || !currentMonthTransactionData.value.dailyTotalAmounts[getDay(dateTime)]; + const dateTime = parseDateTimeFromUnixTime(getActualUnixTimeForStore(getUnixTimeFromLocalDatetime(date), getTimezoneOffsetMinutes(), getBrowserTimezoneOffsetMinutes())); + return !currentMonthTransactionData.value || !currentMonthTransactionData.value.dailyTotalAmounts || !currentMonthTransactionData.value.dailyTotalAmounts[dateTime.getGregorianCalendarDay()]; } const canAddTransaction = computed(() => { @@ -291,12 +287,11 @@ export function useTransactionListPageBase() { } function getDisplayLongDate(transaction: Transaction): string { - const transactionTime = getUnixTime(parseDateFromUnixTime(transaction.time, transaction.utcOffset, currentTimezoneOffsetMinutes.value)); - return formatUnixTimeToLongDate(transactionTime); + return formatUnixTimeToLongDate(transaction.time, transaction.utcOffset, currentTimezoneOffsetMinutes.value); } function getDisplayLongYearMonth(transactionMonthList: TransactionMonthList): string { - return formatUnixTimeToLongYearMonth(getYearMonthFirstUnixTime(transactionMonthList.yearMonth)); + return formatUnixTimeToLongYearMonth(getYearMonthFirstUnixTime(transactionMonthList.yearDashMonth)); } function getDisplayTimezone(transaction: Transaction): string { diff --git a/src/views/desktop/overview/cards/MonthlyIncomeAndExpenseCard.vue b/src/views/desktop/overview/cards/MonthlyIncomeAndExpenseCard.vue index 8b5fe218..d9afa171 100644 --- a/src/views/desktop/overview/cards/MonthlyIncomeAndExpenseCard.vue +++ b/src/views/desktop/overview/cards/MonthlyIncomeAndExpenseCard.vue @@ -41,10 +41,7 @@ import { DISPLAY_HIDDEN_AMOUNT, INCOMPLETE_AMOUNT_SUFFIX } from '@/consts/numera import { type TransactionMonthlyIncomeAndExpenseData } from '@/models/transaction.ts'; -import { - parseDateFromUnixTime, - getMonthName -} from '@/lib/datetime.ts'; +import { parseDateTimeFromUnixTime } from '@/lib/datetime.ts'; import { getExpenseAndIncomeAmountColor } from '@/lib/ui/common.ts'; export interface MonthlyIncomeAndExpenseCardClickEvent { @@ -100,7 +97,7 @@ const chartOptions = computed(() => { if (props.data) { for (let i = 0; i < props.data.length; i++) { const item = props.data[i]; - const month = getMonthName(parseDateFromUnixTime(item.monthStartTime)); + const month = parseDateTimeFromUnixTime(item.monthStartTime).getGregorianCalendarMonthName(); monthNames.push(getMonthShortName(month)); incomeAmounts.push(item.incomeAmount); diff --git a/src/views/desktop/statistics/TransactionPage.vue b/src/views/desktop/statistics/TransactionPage.vue index 351761d2..b07a6ce8 100644 --- a/src/views/desktop/statistics/TransactionPage.vue +++ b/src/views/desktop/statistics/TransactionPage.vue @@ -358,7 +358,7 @@ import { useTransactionCategoriesStore } from '@/stores/transactionCategory.ts'; import { type TransactionStatisticsPartialFilter, useStatisticsStore } from '@/stores/statistics.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 { StatisticsAnalysisType, @@ -375,7 +375,7 @@ import { arrayItemToObjectField } from '@/lib/common.ts'; import { - getYearAndMonthFromUnixTime, + getGregorianCalendarYearAndMonthFromUnixTime, getYearMonthFirstUnixTime, getYearMonthLastUnixTime, getShiftedDateRangeAndDateType, @@ -407,8 +407,8 @@ interface TransactionStatisticsProps { initChartDataType?: string, initChartType?: string, initChartDateType?: string, - initStartTime?: string, - initEndTime?: string, + initStartTime?: TextualYearMonth | '', + initEndTime?: TextualYearMonth | '', initFilterAccountIds?: string, initFilterCategoryIds?: string, initTagIds?: string, @@ -814,8 +814,8 @@ function setDateFilter(dateType: number): void { } else if (analysisType.value === StatisticsAnalysisType.TrendAnalysis) { changed = statisticsStore.updateTransactionStatisticsFilter({ trendChartDateType: dateRange.dateType, - trendChartStartYearMonth: getYearAndMonthFromUnixTime(dateRange.minTime), - trendChartEndYearMonth: getYearAndMonthFromUnixTime(dateRange.maxTime) + trendChartStartYearMonth: getGregorianCalendarYearAndMonthFromUnixTime(dateRange.minTime), + 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) { return; } @@ -882,8 +882,8 @@ function shiftDateRange(scale: number): void { changed = statisticsStore.updateTransactionStatisticsFilter({ trendChartDateType: newDateRange.dateType, - trendChartStartYearMonth: getYearAndMonthFromUnixTime(newDateRange.minTime), - trendChartEndYearMonth: getYearAndMonthFromUnixTime(newDateRange.maxTime) + trendChartStartYearMonth: getGregorianCalendarYearAndMonthFromUnixTime(newDateRange.minTime), + trendChartEndYearMonth: getGregorianCalendarYearAndMonthFromUnixTime(newDateRange.maxTime) }); } @@ -992,8 +992,8 @@ onBeforeRouteUpdate((to) => { initChartDataType: (to.query['chartDataType'] as string | null) || undefined, initChartType: (to.query['chartType'] as string | null) || undefined, initChartDateType: (to.query['chartDateType'] as string | null) || undefined, - initStartTime: (to.query['startTime'] as string | null) || undefined, - initEndTime: (to.query['endTime'] as string | null) || undefined, + initStartTime: (to.query['startTime'] as TextualYearMonth | null) || undefined, + initEndTime: (to.query['endTime'] as TextualYearMonth | null) || undefined, initFilterAccountIds: (to.query['filterAccountIds'] as string | null) || undefined, initFilterCategoryIds: (to.query['filterCategoryIds'] as string | null) || undefined, initTagIds: (to.query['tagIds'] as string | null) || undefined, diff --git a/src/views/desktop/transactions/ListPage.vue b/src/views/desktop/transactions/ListPage.vue index 6870e50a..01a38eac 100644 --- a/src/views/desktop/transactions/ListPage.vue +++ b/src/views/desktop/transactions/ListPage.vue @@ -165,7 +165,7 @@ - + v-if="pageType === TransactionListPageType.List.type && (idx === 0 || (idx > 0 && (transaction.gregorianCalendarYearDashMonthDashDay !== transactions[idx - 1].gregorianCalendarYearDashMonthDashDay)))">
{{ getDisplayLongDate(transaction) }} - {{ getWeekdayLongName(transaction.dayOfWeek) }} + v-if="transaction.displayDayOfWeek"> + {{ getWeekdayLongName(transaction.displayDayOfWeek) }}
@@ -689,6 +689,7 @@ import { useDesktopPageStore } from '@/stores/desktopPage.ts'; import type { TypeAndDisplayName } from '@/core/base.ts'; import { + type Year0BasedMonth, type LocalizedRecentMonthDateRange, type TimeRangeAndDateType, DateRangeScene, @@ -710,9 +711,7 @@ import { } from '@/lib/common.ts'; import { getCurrentUnixTime, - parseDateFromUnixTime, - getYear, - getMonth, + parseDateTimeFromUnixTime, getBrowserTimezoneOffsetMinutes, getActualUnixTimeForStore, getDayFirstUnixTimeBySpecifiedUnixTime, @@ -960,7 +959,7 @@ const transactions = computed(() => { for (let i = 0; i < transactionData.items.length; i++) { const transaction = transactionData.items[i]; - if (transaction.date === currentCalendarDate.value) { + if (transaction.gregorianCalendarYearDashMonthDashDay === currentCalendarDate.value) { transactions.push(transaction); } } @@ -1208,9 +1207,9 @@ function reload(force: boolean, init: boolean): void { } if (queryMonthlyData.value) { - const currentMonthMinDate = parseDateFromUnixTime(query.value.minTime); - const currentYear = getYear(currentMonthMinDate); - const currentMonth = getMonth(currentMonthMinDate); + const currentMonthMinDate = parseDateTimeFromUnixTime(query.value.minTime); + const currentYear = currentMonthMinDate.getGregorianCalendarYear(); + const currentMonth = currentMonthMinDate.getGregorianCalendarMonth(); return transactionsStore.loadMonthlyAllTransactions({ year: currentYear, @@ -1362,7 +1361,7 @@ function changeCustomDateFilter(minTime: number, maxTime: number): void { updateUrlWhenChanged(changed); } -function changeCustomMonthDateFilter(yearMonth: string): void { +function changeCustomMonthDateFilter(yearMonth: Year0BasedMonth): void { if (!yearMonth) { return; } diff --git a/src/views/desktop/transactions/import/ImportDialog.vue b/src/views/desktop/transactions/import/ImportDialog.vue index 5c7529de..75c44440 100644 --- a/src/views/desktop/transactions/import/ImportDialog.vue +++ b/src/views/desktop/transactions/import/ImportDialog.vue @@ -936,8 +936,6 @@ import { import { generateRandomUUID } from '@/lib/misc.ts'; import logger from '@/lib/logger.ts'; import { - parseDateFromUnixTime, - getUnixTime, getUtcOffsetByUtcOffsetMinutes, getTimezoneOffsetMinutes } from '@/lib/datetime.ts'; @@ -1655,8 +1653,7 @@ function isTagValid(tagIds: string[], tagIndex: number): boolean { } function getDisplayDateTime(transaction: ImportTransaction): string { - const transactionTime = getUnixTime(parseDateFromUnixTime(transaction.time, transaction.utcOffset, currentTimezoneOffsetMinutes.value)); - return formatUnixTimeToLongDateTime(transactionTime); + return formatUnixTimeToLongDateTime(transaction.time, transaction.utcOffset, currentTimezoneOffsetMinutes.value); } function getDisplayTimezone(transaction: ImportTransaction): string { diff --git a/src/views/mobile/settings/TextSizeSettingsPage.vue b/src/views/mobile/settings/TextSizeSettingsPage.vue index 79d29238..606a1dda 100644 --- a/src/views/mobile/settings/TextSizeSettingsPage.vue +++ b/src/views/mobile/settings/TextSizeSettingsPage.vue @@ -125,7 +125,7 @@ import { useSettingsStore } from '@/stores/setting.ts'; import { TextDirection } from '@/core/text.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'; const props = defineProps<{ @@ -149,8 +149,8 @@ const fontSize = ref(settingsStore.appSettings.fontSize); const textDirection = computed(() => getCurrentLanguageTextDirection()); const fontSizePreviewClassName = computed(() => getFontSizePreviewClassName(fontSize.value)); const currentLongYearMonth = computed(() => formatUnixTimeToLongYearMonth(currentUnixTime.value)); -const currentDayOfMonth = computed(() => getDay(getLocalDatetimeFromUnixTime(currentUnixTime.value))); -const currentDayOfWeek = computed(() => getWeekdayShortName(getDayOfWeekName(getLocalDatetimeFromUnixTime(currentUnixTime.value)))); +const currentDayOfMonth = computed(() => parseDateTimeFromUnixTime(currentUnixTime.value).getLocalizedCalendarDay()); +const currentDayOfWeek = computed(() => getWeekdayShortName(parseDateTimeFromUnixTime(currentUnixTime.value).getWeekDay())); const currentShortTime = computed(() => formatUnixTimeToShortTime(currentUnixTime.value)); function getFontSizeName(): string { diff --git a/src/views/mobile/statistics/TransactionPage.vue b/src/views/mobile/statistics/TransactionPage.vue index 2ec8dc5d..c96a5b5e 100644 --- a/src/views/mobile/statistics/TransactionPage.vue +++ b/src/views/mobile/statistics/TransactionPage.vue @@ -344,7 +344,7 @@ import { useStatisticsStore } from '@/stores/statistics.ts'; import type { TypeAndDisplayName } from '@/core/base.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 { StatisticsAnalysisType, CategoricalChartType, @@ -355,7 +355,7 @@ import { import { isString, isNumber } from '@/lib/common.ts'; import { - getYearAndMonthFromUnixTime, + getGregorianCalendarYearAndMonthFromUnixTime, getYearMonthFirstUnixTime, getYearMonthLastUnixTime, getShiftedDateRangeAndDateType, @@ -626,8 +626,8 @@ function setDateFilter(dateType: number): void { } else if (analysisType.value === StatisticsAnalysisType.TrendAnalysis) { changed = statisticsStore.updateTransactionStatisticsFilter({ trendChartDateType: dateRange.dateType, - trendChartStartYearMonth: getYearAndMonthFromUnixTime(dateRange.minTime), - trendChartEndYearMonth: getYearAndMonthFromUnixTime(dateRange.maxTime) + trendChartStartYearMonth: getGregorianCalendarYearAndMonthFromUnixTime(dateRange.minTime), + 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) { return; } @@ -692,8 +692,8 @@ function shiftDateRange(scale: number): void { changed = statisticsStore.updateTransactionStatisticsFilter({ trendChartDateType: newDateRange.dateType, - trendChartStartYearMonth: getYearAndMonthFromUnixTime(newDateRange.minTime), - trendChartEndYearMonth: getYearAndMonthFromUnixTime(newDateRange.maxTime) + trendChartStartYearMonth: getGregorianCalendarYearAndMonthFromUnixTime(newDateRange.minTime), + trendChartEndYearMonth: getGregorianCalendarYearAndMonthFromUnixTime(newDateRange.maxTime) }); } diff --git a/src/views/mobile/transactions/EditPage.vue b/src/views/mobile/transactions/EditPage.vue index f6f32f75..ab5faeb6 100644 --- a/src/views/mobile/transactions/EditPage.vue +++ b/src/views/mobile/transactions/EditPage.vue @@ -536,7 +536,7 @@ const { getMultiWeekdayLongNames, formatUnixTimeToLongDate, formatUnixTimeToLongTime, - formatDateToLongDate + formatGregorianCalendarYearDashMonthDashDayToLongDate } = useI18n(); const { showAlert, showConfirm, showToast, routeBackOnError } = useI18nUIComponents(); @@ -754,7 +754,7 @@ const transactionDisplayScheduledStartDate = computed(() => { const template = transaction.value as TransactionTemplate; if (template.scheduledStartDate) { - return formatDateToLongDate(template.scheduledStartDate); + return formatGregorianCalendarYearDashMonthDashDayToLongDate(template.scheduledStartDate); } else { return tt('No limit'); } @@ -768,7 +768,7 @@ const transactionDisplayScheduledEndDate = computed(() => { const template = transaction.value as TransactionTemplate; if (template.scheduledEndDate) { - return formatDateToLongDate(template.scheduledEndDate); + return formatGregorianCalendarYearDashMonthDashDayToLongDate(template.scheduledEndDate); } else { return tt('No limit'); } diff --git a/src/views/mobile/transactions/ListPage.vue b/src/views/mobile/transactions/ListPage.vue index 50750cf5..b00ed7d0 100644 --- a/src/views/mobile/transactions/ListPage.vue +++ b/src/views/mobile/transactions/ListPage.vue @@ -67,7 +67,7 @@ - + :key="transactionMonthList.yearDashMonth" v-for="(transactionMonthList) in transactions"> - +
- {{ transaction.day }} + {{ transaction.gregorianCalendarDayOfMonth }} - - {{ getWeekdayShortName(transaction.dayOfWeek) }} + + {{ getWeekdayShortName(transaction.displayDayOfWeek) }}
@@ -620,9 +620,11 @@ import { type TransactionMonthList, useTransactionsStore } from '@/stores/transa import type { TypeAndDisplayName } from '@/core/base.ts'; import { TextDirection } from '@/core/text.ts'; import { + type TextualYearMonth, + type Year0BasedMonth, type TimeRangeAndDateType, DateRangeScene, - DateRange, + DateRange } from '@/core/datetime.ts'; import { AmountFilterType } from '@/core/numeral.ts'; import { TransactionType } from '@/core/transaction.ts'; @@ -635,11 +637,9 @@ import { } from '@/lib/common.ts'; import { getCurrentUnixTime, - parseDateFromUnixTime, + parseDateTimeFromUnixTime, getBrowserTimezoneOffsetMinutes, getActualUnixTimeForStore, - getYear, - getMonth, getDayFirstUnixTimeBySpecifiedUnixTime, getYearMonthFirstUnixTime, getYearMonthLastUnixTime, @@ -731,8 +731,8 @@ const transactionsStore = useTransactionsStore(); const loadingError = ref(null); const loadingMore = ref(false); const transactionToDelete = ref(null); -const transactionInvisibleYearMonths = ref>({}); -const transactionYearMonthListHeights = ref>({}); +const transactionInvisibleYearMonths = ref>({}); +const transactionYearMonthListHeights = ref>({}); const showTransactionListPageTypePopover = ref(false); const showDatePopover = ref(false); const showCategoryPopover = ref(false); @@ -768,7 +768,7 @@ const transactions = computed(() => { for (let i = 0; i < transactionData.items.length; i++) { const transaction = transactionData.items[i]; - if (transaction.date === currentCalendarDate.value) { + if (transaction.gregorianCalendarYearDashMonthDashDay === currentCalendarDate.value) { transactions.push(transaction); } } @@ -776,7 +776,7 @@ const transactions = computed(() => { const dailyTransactionList: TransactionMonthList = { year: currentMonthTransactionData.value.year, month: currentMonthTransactionData.value.month, - yearMonth: currentMonthTransactionData.value.yearMonth, + yearDashMonth: currentMonthTransactionData.value.yearDashMonth, opened: true, items: transactions, totalAmount: { @@ -809,11 +809,11 @@ const noTransaction = computed(() => { const hasMoreTransaction = computed(() => transactionsStore.hasMoreTransaction); -function getTransactionMonthTitleDomId(yearMonth: string): string { +function getTransactionMonthTitleDomId(yearMonth: TextualYearMonth): string { return 'transaction_month_title_' + yearMonth; } -function getTransactionMonthListDomId(yearMonth: string): string { +function getTransactionMonthListDomId(yearMonth: TextualYearMonth): string { return 'transaction_month_list_' + yearMonth; } @@ -822,7 +822,7 @@ function getTransactionDomId(transaction: Transaction): string { } function isTransactionMonthListInvisible(transactionMonthList: TransactionMonthList): boolean { - if (!transactionYearMonthListHeights.value[transactionMonthList.yearMonth]) { + if (!transactionYearMonthListHeights.value[transactionMonthList.yearDashMonth]) { return false; } @@ -830,7 +830,7 @@ function isTransactionMonthListInvisible(transactionMonthList: TransactionMonthL return true; } - if (transactionInvisibleYearMonths.value[transactionMonthList.yearMonth]) { + if (transactionInvisibleYearMonths.value[transactionMonthList.yearDashMonth]) { return true; } @@ -839,7 +839,7 @@ function isTransactionMonthListInvisible(transactionMonthList: TransactionMonthL function getTransactionMonthListHeight(transactionMonthList: TransactionMonthList): string { if (isTransactionMonthListInvisible(transactionMonthList)) { - return transactionYearMonthListHeights.value[transactionMonthList.yearMonth] + 'px'; + return transactionYearMonthListHeights.value[transactionMonthList.yearDashMonth] + 'px'; } return 'auto'; @@ -857,12 +857,12 @@ function setTransactionMonthListHeights(reset: boolean): Promise { for (let i = 0; i < transactions.value.length - 1; i++) { const transactionMonthList = transactions.value[i]; - const yearMonth = transactionMonthList.yearMonth; - const domId = getTransactionMonthListDomId(yearMonth); + const yearDashMonth = transactionMonthList.yearDashMonth; + const domId = getTransactionMonthListDomId(yearDashMonth); const height = heights[domId]; - if (!transactionYearMonthListHeights.value[yearMonth] && isNumber(height)) { - transactionYearMonthListHeights.value[yearMonth] = height; + if (!transactionYearMonthListHeights.value[yearDashMonth] && isNumber(height)) { + transactionYearMonthListHeights.value[yearDashMonth] = height; } } } @@ -876,30 +876,30 @@ function setTransactionInvisibleYearMonthList(): void { for (let i = 0; i < transactions.value.length - 1; 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}`); if (!titleRect) { continue; } - const listHeight = transactionYearMonthListHeights.value[yearMonth] || 0; + const listHeight = transactionYearMonthListHeights.value[yearDashMonth] || 0; const listRectTop = titleRect.top + titleRect.height; const listRectBottom = listRectTop + listHeight; const invisible = listRectTop > 2 * window.innerHeight || listRectBottom < -2 * window.innerHeight; if (invisible) { - transactionInvisibleYearMonths.value[yearMonth] = true; + transactionInvisibleYearMonths.value[yearDashMonth] = true; } else { - delete transactionInvisibleYearMonths.value[yearMonth]; + delete transactionInvisibleYearMonths.value[yearDashMonth]; } } } function getTransactionDateStyle(transaction: Transaction, previousTransaction: Transaction | null): Record { - if (!previousTransaction || transaction.day !== previousTransaction.day) { + if (!previousTransaction || transaction.gregorianCalendarDayOfMonth !== previousTransaction.gregorianCalendarDayOfMonth) { return {}; } @@ -974,9 +974,9 @@ function reload(done?: () => void): void { transactionTagsStore.loadAllTags({ force: false }) ]).then(() => { if (queryMonthlyData.value) { - const currentMonthMinDate = parseDateFromUnixTime(query.value.minTime); - const currentYear = getYear(currentMonthMinDate); - const currentMonth = getMonth(currentMonthMinDate); + const currentMonthMinDate = parseDateTimeFromUnixTime(query.value.minTime); + const currentYear = currentMonthMinDate.getGregorianCalendarYear(); + const currentMonth = currentMonthMinDate.getGregorianCalendarMonth(); return transactionsStore.loadMonthlyAllTransactions({ 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) { return; } @@ -1466,8 +1466,8 @@ function collapseTransactionMonthList(monthList: TransactionMonthList, collapse: collapse: collapse }); - if (!collapse && transactionInvisibleYearMonths.value[monthList.yearMonth]) { - delete transactionInvisibleYearMonths.value[monthList.yearMonth]; + if (!collapse && transactionInvisibleYearMonths.value[monthList.yearDashMonth]) { + delete transactionInvisibleYearMonths.value[monthList.yearDashMonth]; } }