diff --git a/src/app/file-browser/components/file-list-item/file-list-item.component.html b/src/app/file-browser/components/file-list-item/file-list-item.component.html
index ec76d890c..4e0d8e311 100644
--- a/src/app/file-browser/components/file-list-item/file-list-item.component.html
+++ b/src/app/file-browser/components/file-list-item/file-list-item.component.html
@@ -90,10 +90,10 @@
@if (!showAccess || !item.ShareArchiveVO) {
- {{ item.displayDT | prDate: item.TimezoneVO : 'date' }}
+ {{ startDisplayTime | prDate: item.TimezoneVO : 'date' }}
@if (item.dataStatus > 0) {
{{
- item.displayDT | prDate: item.TimezoneVO : 'time'
+ startDisplayTime | prDate: item.TimezoneVO : 'time'
}}
}
@@ -112,12 +112,12 @@
@if (item.dataStatus > 0) {
- {{ item.displayDT | prDate: item.TimezoneVO : 'date' }}
+ {{ startDisplayTime | prDate: item.TimezoneVO : 'date' }}
}
@if (item.dataStatus > 0) {
- {{ item.displayDT | prDate: item.TimezoneVO : 'time' }}
+ {{ startDisplayTime | prDate: item.TimezoneVO : 'time' }}
}
diff --git a/src/app/file-browser/components/file-list-item/file-list-item.component.spec.ts b/src/app/file-browser/components/file-list-item/file-list-item.component.spec.ts
index 1e78be409..8a9e6b825 100644
--- a/src/app/file-browser/components/file-list-item/file-list-item.component.spec.ts
+++ b/src/app/file-browser/components/file-list-item/file-list-item.component.spec.ts
@@ -25,8 +25,8 @@ class MockItemTypeIconPipe implements PipeTransform {
@Pipe({ name: 'prDate' })
export class MockPrDatePipe implements PipeTransform {
- transform(value: any, format?: string): string {
- return `mocked-date${format ? `-${format}` : ''}`;
+ transform(value: any, ...args: any[]): string {
+ return String(value ?? '');
}
}
@@ -342,4 +342,51 @@ describe('FileListItemComponent', () => {
expect(component.recordThumbnailUrl).toBe('https://example.com/thumb.jpg');
});
+
+ it('should display displayTime instead of displayDT when displayTime is set', () => {
+ component.item.displayTime = '2020-06-10';
+ component.item.displayDT = '2023-01-01T00:00:00.000Z';
+ fixture.detectChanges();
+
+ const secondRowDate =
+ fixture.nativeElement.querySelector('.second-row span')?.textContent;
+
+ expect(secondRowDate).toContain('2020-06-10');
+ expect(secondRowDate).not.toContain('2023-01-01');
+ });
+
+ it('should display displayDT when displayTime is not set', () => {
+ component.item.displayTime = undefined;
+ component.item.displayDT = '2023-01-01T00:00:00.000Z';
+ fixture.detectChanges();
+
+ const secondRowDate =
+ fixture.nativeElement.querySelector('.second-row span')?.textContent;
+
+ expect(secondRowDate).toContain('2023-01-01T00:00:00.000Z');
+ });
+
+ it('should display only the start date when displayTime is an EDTF interval', () => {
+ component.item.displayTime = '2020-06-10/2026-06-15';
+ component.item.displayDT = '2023-01-01T00:00:00.000Z';
+ fixture.detectChanges();
+
+ const secondRowDate =
+ fixture.nativeElement.querySelector('.second-row span')?.textContent;
+
+ expect(secondRowDate).toContain('2020-06-10');
+ expect(secondRowDate).not.toContain('2026-06-15');
+ expect(secondRowDate).not.toContain('2023-01-01');
+ });
+
+ it('should fall back to displayDT when the EDTF interval has an open start', () => {
+ component.item.displayTime = '../2026-06-15';
+ component.item.displayDT = '2023-01-01T00:00:00.000Z';
+ fixture.detectChanges();
+
+ const secondRowDate =
+ fixture.nativeElement.querySelector('.second-row span')?.textContent;
+
+ expect(secondRowDate).toContain('2023-01-01T00:00:00.000Z');
+ });
});
diff --git a/src/app/file-browser/components/file-list-item/file-list-item.component.ts b/src/app/file-browser/components/file-list-item/file-list-item.component.ts
index 21312a7d5..bceed689e 100644
--- a/src/app/file-browser/components/file-list-item/file-list-item.component.ts
+++ b/src/app/file-browser/components/file-list-item/file-list-item.component.ts
@@ -33,6 +33,7 @@ import {
} from '@root/app/models';
import { DataStatus } from '@models/data-status.enum';
import { EditService } from '@core/services/edit/edit.service';
+import { EdtfService } from '@shared/services/edtf-service/edtf.service';
import {
RecordResponse,
FolderResponse,
@@ -247,8 +248,16 @@ export class FileListItemComponent
private storage: StorageService,
@Inject(DOCUMENT) private document: Document,
private shareLinksService: ShareLinksService,
+ private edtfService: EdtfService,
) {}
+ get startDisplayTime(): string {
+ return (
+ this.edtfService.getEdtfIntervalStartDate(this.item.displayTime) ||
+ this.item.displayDT
+ );
+ }
+
async ngOnInit() {
this.recordThumbnailUrl = GetThumbnail(this.item);
const date = new Date(this.item.displayDT);
diff --git a/src/app/shared/pipes/pr-date.pipe.spec.ts b/src/app/shared/pipes/pr-date.pipe.spec.ts
index b65031384..0676b7c38 100644
--- a/src/app/shared/pipes/pr-date.pipe.spec.ts
+++ b/src/app/shared/pipes/pr-date.pipe.spec.ts
@@ -1,5 +1,13 @@
+import { TimezoneVOData } from '@models';
import { PrDatePipe } from './pr-date.pipe';
+const cdtTimezone: TimezoneVOData = {
+ dstAbbrev: 'CDT',
+ dstOffset: '-05:00',
+ stdAbbrev: 'CST',
+ stdOffset: '-06:00',
+};
+
describe('PrDatePipe', () => {
it('create an instance', () => {
const pipe = new PrDatePipe();
@@ -7,6 +15,54 @@ describe('PrDatePipe', () => {
expect(pipe).toBeTruthy();
});
+ it('returns undefined for empty string', () => {
+ const pipe = new PrDatePipe();
+
+ expect(pipe.transform('')).toBeUndefined();
+ });
+
+ it('returns undefined for null', () => {
+ const pipe = new PrDatePipe();
+
+ expect(pipe.transform(null as any)).toBeUndefined();
+ });
+
+ describe('date-only strings (no T)', () => {
+ it('returns the date formatted from UTC', () => {
+ const pipe = new PrDatePipe();
+
+ expect(pipe.transform('2020-06-10')).toBe('2020-06-10');
+ });
+
+ it('returns the date when part is date', () => {
+ const pipe = new PrDatePipe();
+
+ expect(pipe.transform('2020-06-10', undefined, 'date')).toBe(
+ '2020-06-10',
+ );
+ });
+
+ it('returns undefined when part is time', () => {
+ const pipe = new PrDatePipe();
+
+ expect(pipe.transform('2020-06-10', undefined, 'time')).toBeUndefined();
+ });
+
+ it('does not shift date by timezone offset', () => {
+ const pipe = new PrDatePipe();
+
+ expect(pipe.transform('2020-06-10', cdtTimezone, 'date')).toBe(
+ '2020-06-10',
+ );
+ });
+
+ it('returns undefined for time part even with a timezone', () => {
+ const pipe = new PrDatePipe();
+
+ expect(pipe.transform('2020-06-10', cdtTimezone, 'time')).toBeUndefined();
+ });
+ });
+
// it('transforms a DST date in Pacific time', () => {
// const pipe = new PrDatePipe();
// const displayDT = formatDateISOString('2017-05-13T16:36:29.000000');
diff --git a/src/app/shared/pipes/pr-date.pipe.ts b/src/app/shared/pipes/pr-date.pipe.ts
index 96e38ab8a..5bc2877bf 100644
--- a/src/app/shared/pipes/pr-date.pipe.ts
+++ b/src/app/shared/pipes/pr-date.pipe.ts
@@ -35,6 +35,11 @@ export class PrDatePipe implements PipeTransform {
return;
}
+ if (typeof dtString === 'string' && !dtString.includes('T')) {
+ if (part === 'time') return;
+ return moment.utc(dtString).format(MOMENT_DATE_FORMAT.date);
+ }
+
const dt = moment.utc(dtString);
let outputDt: moment.Moment;
diff --git a/src/app/shared/services/edtf-service/edtf.service.spec.ts b/src/app/shared/services/edtf-service/edtf.service.spec.ts
index 2f86e5f4a..400dc5e1c 100644
--- a/src/app/shared/services/edtf-service/edtf.service.spec.ts
+++ b/src/app/shared/services/edtf-service/edtf.service.spec.ts
@@ -1283,4 +1283,42 @@ describe('EdtfService', () => {
expect(result).toBe(edtfString);
});
});
+
+ describe('getEdtfIntervalStartDate', () => {
+ it('should return the start date of an interval', () => {
+ expect(service.getEdtfIntervalStartDate('1985-05-20/1990-06-15')).toBe(
+ '1985-05-20',
+ );
+ });
+
+ it('should preserve the wall-clock time and offset of the start', () => {
+ expect(
+ service.getEdtfIntervalStartDate(
+ '2020-06-10T06:58:00-05:00/2026-06-15T00:00:00Z',
+ ),
+ ).toBe('2020-06-10T06:58:00-05:00');
+ });
+
+ it('should return a non-interval value unchanged', () => {
+ expect(service.getEdtfIntervalStartDate('1985-05-20')).toBe('1985-05-20');
+ });
+
+ it('should return an empty string for an empty input', () => {
+ expect(service.getEdtfIntervalStartDate('')).toBe('');
+ });
+
+ it('should return an empty string for an undefined input', () => {
+ expect(service.getEdtfIntervalStartDate(undefined)).toBe('');
+ });
+
+ it('should return an empty string for an open-ended start', () => {
+ expect(service.getEdtfIntervalStartDate('../1990-06-15')).toBe('');
+ });
+
+ it('should return the start when the end is open-ended', () => {
+ expect(service.getEdtfIntervalStartDate('1985-05-20/..')).toBe(
+ '1985-05-20',
+ );
+ });
+ });
});
diff --git a/src/app/shared/services/edtf-service/edtf.service.ts b/src/app/shared/services/edtf-service/edtf.service.ts
index 8cc7dd34d..14ed0f385 100644
--- a/src/app/shared/services/edtf-service/edtf.service.ts
+++ b/src/app/shared/services/edtf-service/edtf.service.ts
@@ -102,6 +102,19 @@ export class EdtfService {
}
}
+ getEdtfIntervalStartDate(edtfString: string | undefined): string {
+ if (!edtfString) {
+ return '';
+ }
+
+ if (!edtfString.includes('/')) {
+ return edtfString;
+ }
+
+ const [startPart] = edtfString.split('/');
+ return startPart === '..' ? '' : (startPart ?? '');
+ }
+
private parseInterval(edtfString: string): DateTimeModel | null {
const [startPart, endPart] = edtfString.split('/');