diff --git a/package.json b/package.json
index 2f7a459e523..deeb6b60d4f 100644
--- a/package.json
+++ b/package.json
@@ -86,6 +86,7 @@
"react-dom": "19.2.6",
"react-helmet": "6.1.0",
"react-lazyload": "3.2.1",
+ "temporal-polyfill": "0.3.0",
"undici": "8.3.0",
"uuid": "13.0.1",
"winston": "patch:winston@3.8.2#./patches/winston-file-descriptor.patch"
@@ -184,4 +185,4 @@
]
},
"packageManager": "yarn@4.9.4"
-}
+}
\ No newline at end of file
diff --git a/src/app/components-webcore/SportDataHeader/head-to-head-v2/components/centre.tsx b/src/app/components-webcore/SportDataHeader/head-to-head-v2/components/centre.tsx
index e8a035d0c57..86b95656f08 100644
--- a/src/app/components-webcore/SportDataHeader/head-to-head-v2/components/centre.tsx
+++ b/src/app/components-webcore/SportDataHeader/head-to-head-v2/components/centre.tsx
@@ -42,7 +42,7 @@ const Centre = ({ data, maxScoreLength }: CentreProps) => {
{shouldShowScores(status) ? (
) : (
-
+
)}
);
diff --git a/src/app/components-webcore/SportDataHeader/head-to-head-v2/components/fixture-time.tsx b/src/app/components-webcore/SportDataHeader/head-to-head-v2/components/fixture-time.tsx
index efa3d9ba4d3..55e6e5d0331 100644
--- a/src/app/components-webcore/SportDataHeader/head-to-head-v2/components/fixture-time.tsx
+++ b/src/app/components-webcore/SportDataHeader/head-to-head-v2/components/fixture-time.tsx
@@ -1,5 +1,7 @@
+import { useEffect, useState } from 'react';
import VisuallyHiddenText from '../../../../components/VisuallyHiddenText';
import styles from '../index.styles';
+import getLocalisedTime from '../helpers/localise-time';
interface TimeData {
displayTimeUK: string;
@@ -7,16 +9,27 @@ interface TimeData {
}
interface TimeProps {
+ date: string;
time: TimeData;
}
-const Time = ({ time }: TimeProps) => (
- <>
-
- {time.accessibleTime}
- >
-);
+const Time = ({ date, time }: TimeProps) => {
+ const [localisedTime, setLocalisedTime] = useState(time.displayTimeUK);
+
+ useEffect(() => {
+ const clientTime = getLocalisedTime(date, time.displayTimeUK);
+ setLocalisedTime(clientTime);
+ }, []);
+
+ return (
+ <>
+
+
+ {localisedTime}
+ >
+ );
+};
export default Time;
diff --git a/src/app/components-webcore/SportDataHeader/head-to-head-v2/helpers/localise-time.ts b/src/app/components-webcore/SportDataHeader/head-to-head-v2/helpers/localise-time.ts
new file mode 100644
index 00000000000..1bc6d67ff31
--- /dev/null
+++ b/src/app/components-webcore/SportDataHeader/head-to-head-v2/helpers/localise-time.ts
@@ -0,0 +1,44 @@
+import 'temporal-polyfill/global';
+
+const getLocalisedTime = (inputDate, inputTime) => {
+ const [, day, monthName, year] = inputDate.split(' ');
+ const [hour, minute] = inputTime.split(':').map(Number);
+
+ const monthIndex =
+ [
+ 'Jan',
+ 'Feb',
+ 'Mar',
+ 'Apr',
+ 'May',
+ 'Jun',
+ 'Jul',
+ 'Aug',
+ 'Sep',
+ 'Oct',
+ 'Nov',
+ 'Dec',
+ ].indexOf(monthName) + 1;
+
+ const ukDateTime = Temporal.ZonedDateTime.from({
+ timeZone: 'Europe/London',
+ year: Number(year),
+ month: monthIndex,
+ day: Number(day),
+ hour,
+ minute,
+ });
+
+ const userLocalDateTime = ukDateTime
+ .withTimeZone(Temporal.Now.timeZoneId())
+ .toLocaleString(undefined, {
+ hour: '2-digit',
+ minute: '2-digit',
+ hour12: false,
+ numberingSystem: 'latn',
+ });
+
+ return userLocalDateTime;
+};
+
+export default getLocalisedTime;
diff --git a/src/app/components-webcore/SportDataHeader/head-to-head-v2/tests/helpers/index.test.ts b/src/app/components-webcore/SportDataHeader/head-to-head-v2/tests/helpers/index.test.ts
new file mode 100644
index 00000000000..ae8e8e7ff7b
--- /dev/null
+++ b/src/app/components-webcore/SportDataHeader/head-to-head-v2/tests/helpers/index.test.ts
@@ -0,0 +1,77 @@
+import 'temporal-polyfill/global';
+import getLocalisedTime from '../../helpers/localise-time';
+
+describe('getLocalisedTime', () => {
+ const originalTimeZoneId = Temporal.Now.timeZoneId;
+
+ afterEach(() => {
+ Temporal.Now.timeZoneId = originalTimeZoneId;
+ });
+
+ it('should return the same time when user is in UK timezone', () => {
+ Temporal.Now.timeZoneId = () => 'Europe/London';
+
+ const result = getLocalisedTime('Sat 15 Jun 2024', '15:00');
+ expect(result).toBe('15:00');
+ });
+
+ it('should convert UK time to CET timezone (1 hour ahead in summer)', () => {
+ Temporal.Now.timeZoneId = () => 'Europe/Paris';
+
+ const result = getLocalisedTime('Sat 15 Jun 2024', '15:00');
+ expect(result).toBe('16:00');
+ });
+
+ it('should convert UK time to EST timezone (5 hours behind in summer)', () => {
+ Temporal.Now.timeZoneId = () => 'America/New_York';
+
+ const result = getLocalisedTime('Sat 15 Jun 2024', '15:00');
+ expect(result).toBe('10:00');
+ });
+
+ it('should handle midnight correctly', () => {
+ Temporal.Now.timeZoneId = () => 'Europe/London';
+
+ const result = getLocalisedTime('Mon 1 Jan 2024', '00:00');
+ expect(result).toBe('00:00');
+ });
+
+ it('should handle day transition when converting to later timezone', () => {
+ Temporal.Now.timeZoneId = () => 'Asia/Tokyo';
+
+ const result = getLocalisedTime('Sat 15 Jun 2024', '20:00');
+ expect(result).toBe('04:00');
+ });
+
+ it('should parse all months correctly', () => {
+ Temporal.Now.timeZoneId = () => 'Europe/London';
+
+ const months = [
+ 'Jan',
+ 'Feb',
+ 'Mar',
+ 'Apr',
+ 'May',
+ 'Jun',
+ 'Jul',
+ 'Aug',
+ 'Sep',
+ 'Oct',
+ 'Nov',
+ 'Dec',
+ ];
+
+ months.forEach((month, index) => {
+ const day = index + 1;
+ const result = getLocalisedTime(`Mon ${day} ${month} 2024`, '12:00');
+ expect(result).toBe('12:00');
+ });
+ });
+
+ it('should handle winter time correctly with GMT offset', () => {
+ Temporal.Now.timeZoneId = () => 'Europe/Paris';
+
+ const result = getLocalisedTime('Sat 15 Jan 2024', '15:00');
+ expect(result).toBe('16:00');
+ });
+});
diff --git a/yarn.lock b/yarn.lock
index 7d387053a0c..927d5329627 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -15866,6 +15866,7 @@ __metadata:
retry: "npm:0.13.1"
storybook: "npm:10.3.6"
supertest: "npm:7.2.2"
+ temporal-polyfill: "npm:0.3.0"
timemachine: "npm:0.3.2"
ts-jest: "npm:29.4.9"
typescript: "npm:5.9.3"