diff --git a/mobile/lib/services/action.service.dart b/mobile/lib/services/action.service.dart index 8d58e7bc8a..0f72656b4c 100644 --- a/mobile/lib/services/action.service.dart +++ b/mobile/lib/services/action.service.dart @@ -203,24 +203,7 @@ class ActionService { initialDateTime = asset?.localDateTime; initialTimeZone = exif?.timeZone; if (initialDateTime != null && initialTimeZone != null) { - try { - final location = getLocation(initialTimeZone); - initialOffset = - TZDateTime.from(initialDateTime, location).timeZoneOffset; - } on LocationNotFoundException { - RegExp re = RegExp( - r'^utc(?:([+-]\d{1,2})(?::(\d{2}))?)?$', - caseSensitive: false, - ); - final m = re.firstMatch(initialTimeZone); - if (m != null) { - final offset = Duration( - hours: int.parse(m.group(1) ?? '0'), - minutes: int.parse(m.group(2) ?? '0'), - ); - initialOffset = offset; - } - } + initialOffset = getTimeZoneOffset(initialDateTime, initialTimeZone); } } @@ -276,4 +259,25 @@ class ActionService { Future> downloadAll(List assets) { return _downloadRepository.downloadAllAssets(assets); } + + static Duration? getTimeZoneOffset(DateTime dateTime, String timeZone) { + try { + final location = getLocation(timeZone); + return TZDateTime.from(dateTime, location).timeZoneOffset; + } on LocationNotFoundException { + final re = RegExp( + r'^utc(?:([+-]\d{1,2})(?::(\d{2}))?)?$', + caseSensitive: false, + ); + final m = re.firstMatch(timeZone); + if (m != null) { + final offset = Duration( + hours: int.parse(m.group(1) ?? '0'), + minutes: int.parse(m.group(2) ?? '0'), + ); + return offset; + } + return null; + } + } } diff --git a/mobile/test/modules/extensions/timezone_extensions.test.dart b/mobile/test/modules/extensions/timezone_extensions.test.dart new file mode 100644 index 0000000000..b4e17b9653 --- /dev/null +++ b/mobile/test/modules/extensions/timezone_extensions.test.dart @@ -0,0 +1,34 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:timezone/data/latest.dart'; +import 'package:immich_mobile/services/action.service.dart'; + +void main() { + setUpAll(() { + initializeTimeZones(); + }); + + group("Returns timezone offset", () { + final dateTime = DateTime.parse("2025-01-01T00:00:00+0800"); + + test('Returns null with invalid timezone', () { + const timeZone = "#_#"; + final timeZoneOffset = ActionService.getTimeZoneOffset(dateTime, timeZone); + + expect(timeZoneOffset, null); + }); + + test('With timezone as location', () { + const timeZone = "Asia/Hong_Kong"; + final timeZoneOffset = ActionService.getTimeZoneOffset(dateTime, timeZone); + + expect(timeZoneOffset, const Duration(hours: 8)); + }); + + test('With timezone as offset', () { + const timeZone = "utc+08:00"; + final timeZoneOffset = ActionService.getTimeZoneOffset(dateTime, timeZone); + + expect(timeZoneOffset, const Duration(hours: 8)); + }); + }); +}