mirror of
https://github.com/immich-app/immich
synced 2025-11-07 17:27:20 +00:00
fix: regression: sort day by fileCreatedAt again (#18732)
* fix: regression: sort day by fileCreatedAt again * lint * e2e test * inline function * e2e * Address comments. Drop dayGroup and timezone in favor of localOffsetMinutes * lint and some api-doc * lint, more api-doc * format * Move minutes to fractional hours * make sql * merge/conflict * merge fallout, review comments * spelling * drop offset from returned date * move description into decorator where possible, regen api
This commit is contained in:
parent
81423420c8
commit
55f4e93456
23 changed files with 687 additions and 247 deletions
|
|
@ -5,17 +5,81 @@ import { AssetTypeEnum, type AssetResponseDto } from '@immich/sdk';
|
|||
import { DateTime, type LocaleOptions } from 'luxon';
|
||||
import { get } from 'svelte/store';
|
||||
|
||||
// Move type definitions to the top
|
||||
export type TimelinePlainYearMonth = {
|
||||
year: number;
|
||||
month: number;
|
||||
};
|
||||
|
||||
export type TimelinePlainDate = TimelinePlainYearMonth & {
|
||||
day: number;
|
||||
};
|
||||
|
||||
export type TimelinePlainDateTime = TimelinePlainDate & {
|
||||
hour: number;
|
||||
minute: number;
|
||||
second: number;
|
||||
millisecond: number;
|
||||
};
|
||||
|
||||
export type ScrubberListener = (
|
||||
bucketDate: { year: number; month: number },
|
||||
overallScrollPercent: number,
|
||||
bucketScrollPercent: number,
|
||||
) => void | Promise<void>;
|
||||
|
||||
export const fromLocalDateTime = (localDateTime: string) =>
|
||||
DateTime.fromISO(localDateTime, { zone: 'UTC', locale: get(locale) });
|
||||
// used for AssetResponseDto.dateTimeOriginal, amongst others
|
||||
export const fromISODateTime = (isoDateTime: string, timeZone: string): DateTime<true> =>
|
||||
DateTime.fromISO(isoDateTime, { zone: timeZone, locale: get(locale) }) as DateTime<true>;
|
||||
|
||||
export const fromLocalDateTimeToObject = (localDateTime: string): TimelinePlainDateTime =>
|
||||
(fromLocalDateTime(localDateTime) as DateTime<true>).toObject();
|
||||
export const fromISODateTimeToObject = (isoDateTime: string, timeZone: string): TimelinePlainDateTime =>
|
||||
(fromISODateTime(isoDateTime, timeZone) as DateTime<true>).toObject();
|
||||
|
||||
// used for AssetResponseDto.localDateTime, amongst others
|
||||
export const fromISODateTimeUTC = (isoDateTimeUtc: string) => fromISODateTime(isoDateTimeUtc, 'UTC');
|
||||
|
||||
export const fromISODateTimeUTCToObject = (isoDateTimeUtc: string): TimelinePlainDateTime =>
|
||||
(fromISODateTimeUTC(isoDateTimeUtc) as DateTime<true>).toObject();
|
||||
|
||||
// used to create equivalent of AssetResponseDto.localDateTime in UTC, but without timezone information
|
||||
export const fromISODateTimeTruncateTZToObject = (
|
||||
isoDateTimeUtc: string,
|
||||
timeZone: string | undefined,
|
||||
): TimelinePlainDateTime =>
|
||||
(
|
||||
fromISODateTime(isoDateTimeUtc, timeZone ?? 'UTC').setZone('UTC', { keepLocalTime: true }) as DateTime<true>
|
||||
).toObject();
|
||||
|
||||
// Used to derive a local date time from an ISO string and a UTC offset in hours
|
||||
export const fromISODateTimeWithOffsetToObject = (
|
||||
isoDateTimeUtc: string,
|
||||
utcOffsetHours: number,
|
||||
): TimelinePlainDateTime => {
|
||||
const utcDateTime = fromISODateTimeUTC(isoDateTimeUtc);
|
||||
|
||||
// Apply the offset to get the local time
|
||||
// Note: offset is in hours (may be fractional), positive for east of UTC, negative for west
|
||||
const localDateTime = utcDateTime.plus({ hours: utcOffsetHours });
|
||||
|
||||
// Return as plain object (keeping the local time but in UTC zone context)
|
||||
return (localDateTime.setZone('UTC', { keepLocalTime: true }) as DateTime<true>).toObject();
|
||||
};
|
||||
|
||||
export const getTimes = (isoDateTimeUtc: string, localUtcOffsetHours: number) => {
|
||||
const utcDateTime = fromISODateTimeUTC(isoDateTimeUtc);
|
||||
const fileCreatedAt = (utcDateTime as DateTime<true>).toObject();
|
||||
|
||||
// Apply the offset to get the local time
|
||||
// Note: offset is in hours (may be fractional), positive for east of UTC, negative for west
|
||||
const luxonLocalDateTime = utcDateTime.plus({ hours: localUtcOffsetHours });
|
||||
// Return as plain object (keeping the local time but in UTC zone context)
|
||||
const localDateTime = (luxonLocalDateTime.setZone('UTC', { keepLocalTime: true }) as DateTime<true>).toObject();
|
||||
|
||||
return {
|
||||
fileCreatedAt,
|
||||
localDateTime,
|
||||
};
|
||||
};
|
||||
|
||||
export const fromTimelinePlainDateTime = (timelineDateTime: TimelinePlainDateTime): DateTime<true> =>
|
||||
DateTime.fromObject(timelineDateTime, { zone: 'local', locale: get(locale) }) as DateTime<true>;
|
||||
|
|
@ -32,10 +96,7 @@ export const fromTimelinePlainYearMonth = (timelineYearMonth: TimelinePlainYearM
|
|||
{ zone: 'local', locale: get(locale) },
|
||||
) as DateTime<true>;
|
||||
|
||||
export const fromDateTimeOriginal = (dateTimeOriginal: string, timeZone: string) =>
|
||||
DateTime.fromISO(dateTimeOriginal, { zone: timeZone, locale: get(locale) });
|
||||
|
||||
export const toISOLocalDateTime = (timelineYearMonth: TimelinePlainYearMonth): string =>
|
||||
export const toISOYearMonthUTC = (timelineYearMonth: TimelinePlainYearMonth): string =>
|
||||
(fromTimelinePlainYearMonth(timelineYearMonth).setZone('UTC', { keepLocalTime: true }) as DateTime<true>).toISO();
|
||||
|
||||
export function formatBucketTitle(_date: DateTime): string {
|
||||
|
|
@ -104,12 +165,16 @@ export const toTimelineAsset = (unknownAsset: AssetResponseDto | TimelineAsset):
|
|||
const country = assetResponse.exifInfo?.country;
|
||||
const people = assetResponse.people?.map((person) => person.name) || [];
|
||||
|
||||
const localDateTime = fromISODateTimeUTCToObject(assetResponse.localDateTime);
|
||||
const fileCreatedAt = fromISODateTimeToObject(assetResponse.fileCreatedAt, assetResponse.exifInfo?.timeZone ?? 'UTC');
|
||||
|
||||
return {
|
||||
id: assetResponse.id,
|
||||
ownerId: assetResponse.ownerId,
|
||||
ratio,
|
||||
thumbhash: assetResponse.thumbhash,
|
||||
localDateTime: fromLocalDateTimeToObject(assetResponse.localDateTime),
|
||||
localDateTime,
|
||||
fileCreatedAt,
|
||||
isFavorite: assetResponse.isFavorite,
|
||||
visibility: assetResponse.visibility,
|
||||
isTrashed: assetResponse.isTrashed,
|
||||
|
|
@ -151,19 +216,3 @@ export const plainDateTimeCompare = (ascending: boolean, a: TimelinePlainDateTim
|
|||
}
|
||||
return aDateTime.millisecond - bDateTime.millisecond;
|
||||
};
|
||||
|
||||
export type TimelinePlainDateTime = TimelinePlainDate & {
|
||||
hour: number;
|
||||
minute: number;
|
||||
second: number;
|
||||
millisecond: number;
|
||||
};
|
||||
|
||||
export type TimelinePlainDate = TimelinePlainYearMonth & {
|
||||
day: number;
|
||||
};
|
||||
|
||||
export type TimelinePlainYearMonth = {
|
||||
year: number;
|
||||
month: number;
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue