diff --git a/CriticalMapsKit/Sources/Helpers/Timezone+Extras.swift b/CriticalMapsKit/Sources/Helpers/Timezone+Extras.swift index cb06108a..5fbaa0fd 100644 --- a/CriticalMapsKit/Sources/Helpers/Timezone+Extras.swift +++ b/CriticalMapsKit/Sources/Helpers/Timezone+Extras.swift @@ -7,6 +7,7 @@ public extension TimeZone { static let spain = TimeZone(identifier: "Europe/Madrid")! static let france = TimeZone(identifier: "Europe/Paris")! static let greece = TimeZone(identifier: "Europe/Athens")! + static let london = TimeZone(identifier: "Europe/London")! // America static let ecuador = TimeZone(identifier: "America/Guayaquil")! diff --git a/CriticalMapsKit/Sources/SharedModels/NextRideFeature/Ride.swift b/CriticalMapsKit/Sources/SharedModels/NextRideFeature/Ride.swift index 4e09a6fb..c278634b 100644 --- a/CriticalMapsKit/Sources/SharedModels/NextRideFeature/Ride.swift +++ b/CriticalMapsKit/Sources/SharedModels/NextRideFeature/Ride.swift @@ -64,7 +64,18 @@ extension Ride { let id: Int let name: String let timezone: String + + public init( + id: Int, + name: String, + timezone: String + ) { + self.id = id + self.name = name + self.timezone = timezone + } } + } public extension Ride { @@ -159,3 +170,38 @@ private extension Date.FormatStyle { ) } } + +enum Helper { + static func displayEventDateTimeForUser( + eventDateTime: TimeInterval, + eventTimeZoneID: String, + userTimeZoneID: String + ) -> String? { + + // Create Date object from event's Unix timestamp + let eventDate = Date(timeIntervalSince1970: eventDateTime) + + // Get event's timezone + guard let eventTimeZone = TimeZone(identifier: eventTimeZoneID) else { + print("Invalid event timezone") + return nil + } + + // Get user's timezone (e.g., London timezone) + guard let userTimeZone = TimeZone(identifier: userTimeZoneID) else { + print("Invalid user timezone") + return nil + } + + // Formatter to display time in local timezone + let dateFormatter = DateFormatter() + dateFormatter.dateStyle = .full + dateFormatter.timeStyle = .short + + // Convert event time to user's local timezone + dateFormatter.timeZone = userTimeZone + let formattedDateForUser = dateFormatter.string(from: eventDate) + + return formattedDateForUser + } +} diff --git a/CriticalMapsKit/Tests/NextRideFeatureTests/RideTests.swift b/CriticalMapsKit/Tests/NextRideFeatureTests/RideTests.swift deleted file mode 100644 index 0efe1067..00000000 --- a/CriticalMapsKit/Tests/NextRideFeatureTests/RideTests.swift +++ /dev/null @@ -1,90 +0,0 @@ -import ComposableArchitecture -import Helpers -import SharedModels -import XCTest - -final class RideTests: XCTestCase { - func test_rideInGMTTimezone() { - // arrange - let ride = Ride.mock() - - // act - withDependencies { - $0.timeZone = .gmt - } operation: { - XCTAssertEqual( - "20:00", - ride.dateTime.humanReadableTime - ) - } - } - - func test_rideInGermanTimezone() { - // arrange - let ride = Ride.mock() - - // act - withDependencies { - $0.timeZone = .germany - } operation: { - XCTAssertEqual( - "20:00", - ride.dateTime.humanReadableTime - ) - } - } - - func test_rideInGreeceTimezone() { - // arrange - let ride = Ride.mock() - - // act - withDependencies { - $0.timeZone = .greece - $0.calendar = .init(identifier: .gregorian) - } operation: { - XCTAssertEqual( - "20:00", - ride.dateTime.humanReadableTime - ) - } - } - - func test_rideInEcuadorTimezone() { - // arrange - let ride = Ride.mock() - - // act - withDependencies { - $0.timeZone = .ecuador - $0.calendar = .init(identifier: .gregorian) - } operation: { - XCTAssertEqual( - "20:00", - ride.dateTime.humanReadableTime - ) - } - } -} - -extension Ride { - static func mock() -> Self { - Self( - id: 0, - slug: nil, - title: "CriticalMaps Berlin", - description: nil, - dateTime: Date(timeIntervalSince1970: 1711738800), - location: nil, - latitude: 53.1235, - longitude: 13.4234, - estimatedParticipants: nil, - estimatedDistance: nil, - estimatedDuration: nil, - enabled: true, - disabledReason: nil, - disabledReasonMessage: nil, - rideType: .criticalMass - ) - } -} diff --git a/CriticalMapsKit/Tests/NextRideFeatureTests/RideTimeTests.swift b/CriticalMapsKit/Tests/NextRideFeatureTests/RideTimeTests.swift new file mode 100644 index 00000000..11e1c346 --- /dev/null +++ b/CriticalMapsKit/Tests/NextRideFeatureTests/RideTimeTests.swift @@ -0,0 +1,63 @@ +import ComposableArchitecture +import Helpers +import SharedModels +import Foundation +import Testing + +struct RideTimeTests { + @Test("Ride in new york timezone") + func rideWithNewYorkTimezone() { + withDependencies { + $0.locale = Locale(identifier: "en_US") + } operation: { + let ride = Ride.mock(timeZone: .newYork, timestamp: 1727478000) + let rideTime = ride.rideTime + #expect(rideTime == "7:00 PM") + } + } + + @Test("Ride in berlin timezone") + func rideWithBerlinTimezone() { + withDependencies { + $0.locale = Locale(identifier: "de_DE") + } operation: { + let ride = Ride.mock(timeZone: .germany, timestamp: 1725192000) + let rideTime = ride.rideTime + #expect(rideTime == "14:00") + } + } + + @Test("Ride in GMT timezone") + func rideWithGMTTimezone() { + withDependencies { + $0.locale = Locale(identifier: "pt_PT") + } operation: { + let ride = Ride.mock(timeZone: .gmt, timestamp: 1727452800) + let rideTime = ride.rideTime + #expect(rideTime == "16:00") + } + } +} + +private extension Ride { + static func mock(timeZone: TimeZone, timestamp: TimeInterval) -> Self { + Self( + id: 0, + city: Ride.City(id: 1, name: "Berlin", timezone: timeZone.identifier), + slug: nil, + title: "CriticalMaps Berlin", + description: nil, + dateTime: Date(timeIntervalSince1970: timestamp), + location: nil, + latitude: 53.1235, + longitude: 13.4234, + estimatedParticipants: nil, + estimatedDistance: nil, + estimatedDuration: nil, + enabled: true, + disabledReason: nil, + disabledReasonMessage: nil, + rideType: .criticalMass + ) + } +}