From 5aa215e4d711a05b768b1f265154cfecafa6fb88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Sch=C3=B6mer?= Date: Tue, 5 Dec 2023 11:21:19 +0100 Subject: [PATCH] fix toUTCMillis --- nightguard.xcodeproj/project.pbxproj | 12 +- nightguard.xctestplan | 29 +++ .../contents.xcworkspacedata | 3 + nightguard/DateExtension.swift | 36 ++-- nightguardTests/DateExtensionTest.swift | 170 ++++++++++++++++++ 5 files changed, 222 insertions(+), 28 deletions(-) create mode 100644 nightguard.xctestplan create mode 100644 nightguardTests/DateExtensionTest.swift diff --git a/nightguard.xcodeproj/project.pbxproj b/nightguard.xcodeproj/project.pbxproj index 733a365..100037b 100644 --- a/nightguard.xcodeproj/project.pbxproj +++ b/nightguard.xcodeproj/project.pbxproj @@ -345,6 +345,7 @@ 43F1E1121D076C4500C329A2 /* NightscoutService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43F1E1101D076C1C00C329A2 /* NightscoutService.swift */; }; 43F1E11B1D076D9700C329A2 /* TimeService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43F1E11A1D076D9700C329A2 /* TimeService.swift */; }; 43FCE625208B80840080DA0A /* SnoozeAlarmViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43FCE624208B80840080DA0A /* SnoozeAlarmViewController.swift */; }; + 4BD05B7C2B1E33F700A74E9B /* DateExtensionTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BD05B7B2B1E33F700A74E9B /* DateExtensionTest.swift */; }; 7FCFB7190EB96C437CD9908C /* Pods_nightguard.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B5F5A4E6048F7A6F26B9C31E /* Pods_nightguard.framework */; }; BD9486CCE1790AB9D245579D /* Pods_nightguard_Widget_Extension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F5AA741119F937A9FEA0FE16 /* Pods_nightguard_Widget_Extension.framework */; }; C21FEAA8173DC84337CC0E33 /* Pods_nightguard_WatchKit_App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A960E5B86E46012C3B88556F /* Pods_nightguard_WatchKit_App.framework */; }; @@ -710,6 +711,7 @@ 43F1E1101D076C1C00C329A2 /* NightscoutService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = NightscoutService.swift; path = nightguard/NightscoutService.swift; sourceTree = SOURCE_ROOT; }; 43F1E11A1D076D9700C329A2 /* TimeService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TimeService.swift; path = nightguard/TimeService.swift; sourceTree = SOURCE_ROOT; }; 43FCE624208B80840080DA0A /* SnoozeAlarmViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SnoozeAlarmViewController.swift; sourceTree = ""; }; + 4BD05B7B2B1E33F700A74E9B /* DateExtensionTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateExtensionTest.swift; sourceTree = ""; }; 5560CB94CC76B8F0F7F5C440 /* Pods-nightguardTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-nightguardTests.release.xcconfig"; path = "Target Support Files/Pods-nightguardTests/Pods-nightguardTests.release.xcconfig"; sourceTree = ""; }; 77D200A6D5933D628408130C /* Pods_nightguardUITests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_nightguardUITests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 89358A3E8C5372AE643A47B4 /* Pods-nightguard.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-nightguard.debug.xcconfig"; path = "Target Support Files/Pods-nightguard/Pods-nightguard.debug.xcconfig"; sourceTree = ""; }; @@ -1008,6 +1010,7 @@ D112DD3921EB502300ECFB5E /* BloodSugarArrayTest.swift */, D112DD3B21EB507E00ECFB5E /* PredictionServiceTest.swift */, 4389A5262602AADE001F10AD /* TargetDataTest.swift */, + 4BD05B7B2B1E33F700A74E9B /* DateExtensionTest.swift */, ); path = nightguardTests; sourceTree = ""; @@ -1965,6 +1968,7 @@ D1D96CB221F85BC70035A60E /* UserDefaultsValue.swift in Sources */, 432E62D71D0CC35100DD7978 /* NightscoutService.swift in Sources */, D112DD3821EA61A700ECFB5E /* NightscoutCacheService.swift in Sources */, + 4BD05B7C2B1E33F700A74E9B /* DateExtensionTest.swift in Sources */, 432E62D81D0CC38C00DD7978 /* NightscoutData.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -2594,7 +2598,7 @@ ENABLE_BITCODE = NO; EXCLUDED_ARCHS = ""; INFOPLIST_FILE = nightguard/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 14.7; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -2625,7 +2629,7 @@ DEVELOPMENT_TEAM = BSAVUVP8PV; ENABLE_BITCODE = NO; INFOPLIST_FILE = nightguard/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 14.7; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -2649,6 +2653,7 @@ BUNDLE_LOADER = "$(TEST_HOST)"; DEVELOPMENT_TEAM = BSAVUVP8PV; INFOPLIST_FILE = nightguardTests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -2669,6 +2674,7 @@ BUNDLE_LOADER = "$(TEST_HOST)"; DEVELOPMENT_TEAM = BSAVUVP8PV; INFOPLIST_FILE = nightguardTests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -2688,6 +2694,7 @@ buildSettings = { DEVELOPMENT_TEAM = BSAVUVP8PV; INFOPLIST_FILE = nightguardUITests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -2709,6 +2716,7 @@ buildSettings = { DEVELOPMENT_TEAM = BSAVUVP8PV; INFOPLIST_FILE = nightguardUITests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", diff --git a/nightguard.xctestplan b/nightguard.xctestplan new file mode 100644 index 0000000..3bfe31b --- /dev/null +++ b/nightguard.xctestplan @@ -0,0 +1,29 @@ +{ + "configurations" : [ + { + "id" : "78ECACD6-8FC0-4475-B36E-80C6EE6B5044", + "name" : "Test Scheme Action", + "options" : { + + } + } + ], + "defaultOptions" : { + "codeCoverage" : false, + "targetForVariableExpansion" : { + "containerPath" : "container:nightguard.xcodeproj", + "identifier" : "43647BC91BFF6435004389F9", + "name" : "nightguard" + } + }, + "testTargets" : [ + { + "target" : { + "containerPath" : "container:nightguard.xcodeproj", + "identifier" : "43647BDD1BFF6435004389F9", + "name" : "nightguardTests" + } + } + ], + "version" : 1 +} diff --git a/nightguard.xcworkspace/contents.xcworkspacedata b/nightguard.xcworkspace/contents.xcworkspacedata index 4dc13d0..a773393 100644 --- a/nightguard.xcworkspace/contents.xcworkspacedata +++ b/nightguard.xcworkspace/contents.xcworkspacedata @@ -7,4 +7,7 @@ + + diff --git a/nightguard/DateExtension.swift b/nightguard/DateExtension.swift index d4f81a5..a595442 100644 --- a/nightguard/DateExtension.swift +++ b/nightguard/DateExtension.swift @@ -52,41 +52,25 @@ extension Date { return dateFormatter.string(from: self) } + func toUTCMillis() -> String { - return String(Int64((self.toGlobalTime().timeIntervalSince1970 * 1000.0).rounded())) + return String(Int64((self.timeIntervalSince1970 * 1000.0).rounded())) } func convertToIsoDate() -> String { - let dateFormatter = DateFormatter() - dateFormatter.dateFormat = "yyyy-MM-dd" - dateFormatter.locale = Locale(identifier: "en_US") - dateFormatter.timeZone = TimeZone.init(secondsFromGMT: 0) - - return dateFormatter.string(from: self) + return ISO8601DateFormatter.string( + from: self, + timeZone: TimeZone.init(identifier: "UTC")!, + formatOptions: [.withYear, .withMonth, .withDay, .withDashSeparatorInDate] + ) } func convertToIsoDateTime() -> String { - - let dateFormatter = DateFormatter() - dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss'Z'" - - return dateFormatter.string(from: self.toGlobalTime()) - } - - // Convert local time to UTC (or GMT) - func toGlobalTime() -> Date { - let timezone = TimeZone.current - let seconds = -TimeInterval(timezone.secondsFromGMT(for: self)) - return Date(timeInterval: seconds, since: self) - } - - // Convert UTC (or GMT) to local time - func toLocalTime() -> Date { - let timezone = TimeZone.current - let seconds = TimeInterval(timezone.secondsFromGMT(for: self)) - return Date(timeInterval: seconds, since: self) + let dateFormatter = ISO8601DateFormatter() + + return dateFormatter.string(from: self) } func remainingMinutes() -> Int { diff --git a/nightguardTests/DateExtensionTest.swift b/nightguardTests/DateExtensionTest.swift new file mode 100644 index 0000000..d667a82 --- /dev/null +++ b/nightguardTests/DateExtensionTest.swift @@ -0,0 +1,170 @@ +// +// DateExtensionTest.swift +// nightguardTests +// +// Created by Jörg Schömer on 04.12.23. +// + +import XCTest +import Foundation + +final class DateExtensionTest: XCTestCase { + + func testCEST() throws { + // given + let testDate = DateComponents( + calendar: .current, + timeZone: TimeZone.init(identifier: "CEST"), + year: 2023, + month: 6, + day: 7, + hour: 2, + minute: 0, + second: 0 + ).date! + + // when + let mills = Double(testDate.toUTCMillis())! + + // then + // recreate date from mills + // Returns a `Date` initialized relative to 00:00:00 UTC on 1 January 1970 by a given number of seconds. + let millsDate = Date(timeIntervalSince1970: mills / 1000.0) + XCTAssertEqual(millsDate.formatted(Date.ISO8601FormatStyle()), "2023-06-07T00:00:00Z") + } + + func testCET() throws { + // given + let testDate = DateComponents( + calendar: .current, + timeZone: TimeZone.init(identifier: "CET"), + year: 2023, + month: 12, + day: 4, + hour: 19, + minute: 10, + second: 0 + ).date! + + // when + let mills = Double(testDate.toUTCMillis())! + + // then + // recreate date from mills + // Returns a `Date` initialized relative to 00:00:00 UTC on 1 January 1970 by a given number of seconds. + let millsDate = Date(timeIntervalSince1970: mills / 1000.0) + XCTAssertEqual(millsDate.formatted(Date.ISO8601FormatStyle()), "2023-12-04T18:10:00Z") + } + + func testTimeIntervalSince1970CET() throws { + // given + let testDate = DateComponents( + calendar: .current, + timeZone: TimeZone.init(identifier: "CET"), + year: 2023, + month: 12, + day: 4, + hour: 19, + minute: 10, + second: 0 + ).date! + + // when + /** + The interval between the date object and 00:00:00 UTC on 1 January 1970. + + This property's value is negative if the date object is earlier than 00:00:00 UTC on 1 January 1970. + */ + let millisSince1970UTC: Int64 = Int64((testDate.timeIntervalSince1970 * 1000.0).rounded()) + + // then + let utcDate = Date(timeIntervalSince1970: (Double(millisSince1970UTC) / 1000.0)) + XCTAssertEqual(utcDate.formatted(Date.ISO8601FormatStyle()), "2023-12-04T18:10:00Z") + } + + func testTimeIntervalSince1970CEST() throws { + // given + let testDate = DateComponents( + calendar: .current, + timeZone: TimeZone.init(identifier: "CEST"), + year: 2023, + month: 06, + day: 7, + hour: 2, + minute: 0, + second: 0 + ).date! + + // when + /** + The interval between the date object and 00:00:00 UTC on 1 January 1970. + + This property's value is negative if the date object is earlier than 00:00:00 UTC on 1 January 1970. + */ + let millisSince1970UTC: Int64 = Int64((testDate.timeIntervalSince1970 * 1000.0).rounded()) + + // then + let utcDate = Date(timeIntervalSince1970: (Double(millisSince1970UTC) / 1000.0)) + XCTAssertEqual(utcDate.formatted(Date.ISO8601FormatStyle()), "2023-06-07T00:00:00Z") + } + + func testConvertToIsoDateTime() throws { + // given + let testDate = DateComponents( + calendar: .current, + timeZone: TimeZone.init(identifier: "CEST"), + year: 2023, + month: 06, + day: 7, + hour: 2, + minute: 0, + second: 0 + ).date! + + // when + let dateString = testDate.convertToIsoDateTime() + + //then + XCTAssertEqual(dateString, "2023-06-07T00:00:00Z") + } + + func testConvertToIsoDate() throws { + // given + let testDate = DateComponents( + calendar: .current, + timeZone: TimeZone.init(identifier: "CEST"), + year: 2023, + month: 06, + day: 7, + hour: 2, + minute: 0, + second: 0 + ).date! + + // when + let dateString = testDate.convertToIsoDate() + + // then + XCTAssertEqual(dateString, "2023-06-07") + } + + func testToUTCMillis() throws { + // given + let testDate = DateComponents( + calendar: .current, + timeZone: TimeZone.init(identifier: "CEST"), + year: 2023, + month: 06, + day: 7, + hour: 2, + minute: 0, + second: 0 + ).date! + + // when + let millisString = testDate.toUTCMillis() + + // then + XCTAssertEqual(millisString, "1686096000000") + } +}