@@ -2555,6 +2555,73 @@ - (void)test027_AttestationChallenge
2555
2555
[self waitForExpectations: @[ attestationRequestedViaDevice ] timeout: kTimeoutInSeconds ];
2556
2556
}
2557
2557
2558
+ - (void )test028_TimeZoneAndDST
2559
+ {
2560
+ // Time synchronization is marked provisional so far, so we can only test it
2561
+ // when MTR_ENABLE_PROVISIONAL is set.
2562
+ #if MTR_ENABLE_PROVISIONAL
2563
+ dispatch_queue_t queue = dispatch_get_main_queue ();
2564
+
2565
+ __auto_type * device = GetConnectedDevice ();
2566
+ __auto_type * cluster = [[MTRBaseClusterTimeSynchronization alloc ] initWithDevice: device endpointID: @(0 ) queue: queue];
2567
+
2568
+ XCTestExpectation * readTimeZoneExpectation = [self expectationWithDescription: @" Read TimeZone attribute" ];
2569
+ __block NSArray <MTRTimeSynchronizationClusterTimeZoneStruct *> * timeZone;
2570
+ [cluster readAttributeTimeZoneWithCompletion: ^(NSArray * _Nullable value, NSError * _Nullable error) {
2571
+ XCTAssertNil (error);
2572
+ timeZone = value;
2573
+ [readTimeZoneExpectation fulfill ];
2574
+ }];
2575
+
2576
+ [self waitForExpectations: @[ readTimeZoneExpectation ] timeout: kTimeoutInSeconds ];
2577
+
2578
+ __block NSArray <MTRTimeSynchronizationClusterDSTOffsetStruct *> * dstOffset;
2579
+ XCTestExpectation * readDSTOffsetExpectation = [self expectationWithDescription: @" Read DSTOffset attribute" ];
2580
+ [cluster readAttributeDSTOffsetWithCompletion: ^(NSArray * _Nullable value, NSError * _Nullable error) {
2581
+ XCTAssertNil (error);
2582
+ dstOffset = value;
2583
+ [readDSTOffsetExpectation fulfill ];
2584
+ }];
2585
+
2586
+ [self waitForExpectations: @[ readDSTOffsetExpectation ] timeout: kTimeoutInSeconds ];
2587
+
2588
+ // Check that the first DST offset entry matches what we expect. If we
2589
+ // happened to cross a DST boundary during execution of this function, some
2590
+ // of these checks will fail, but that seems pretty low-probability.
2591
+
2592
+ XCTAssertTrue (dstOffset.count > 0 );
2593
+ MTRTimeSynchronizationClusterDSTOffsetStruct * currentDSTOffset = dstOffset[0 ];
2594
+
2595
+ __auto_type * utcTz = [NSTimeZone timeZoneForSecondsFromGMT: 0 ];
2596
+ __auto_type * dateComponents = [[NSDateComponents alloc ] init ];
2597
+ dateComponents.timeZone = utcTz;
2598
+ dateComponents.year = 2000 ;
2599
+ dateComponents.month = 1 ;
2600
+ dateComponents.day = 1 ;
2601
+ NSCalendar * gregorianCalendar = [[NSCalendar alloc ] initWithCalendarIdentifier: NSCalendarIdentifierGregorian ];
2602
+ NSDate * matterEpoch = [gregorianCalendar dateFromComponents: dateComponents];
2603
+
2604
+ NSDate * nextReportedDSTTransition;
2605
+ if (currentDSTOffset.validUntil == nil ) {
2606
+ nextReportedDSTTransition = nil ;
2607
+ } else {
2608
+ double validUntilMicroSeconds = currentDSTOffset.validUntil .doubleValue ;
2609
+ nextReportedDSTTransition = [NSDate dateWithTimeInterval: validUntilMicroSeconds / 1e6 sinceDate: matterEpoch];
2610
+ }
2611
+
2612
+ __auto_type * tz = [NSTimeZone localTimeZone ];
2613
+ NSDate * nextDSTTransition = tz.nextDaylightSavingTimeTransition ;
2614
+ XCTAssertEqualObjects (nextReportedDSTTransition, nextDSTTransition);
2615
+
2616
+ XCTAssertEqual (currentDSTOffset.offset .intValue , tz.daylightSavingTimeOffset );
2617
+
2618
+ // Now check the timezone info we got. We always set exactly one timezone.
2619
+ XCTAssertEqual (timeZone.count , 1 );
2620
+ MTRTimeSynchronizationClusterTimeZoneStruct * currentTimeZone = timeZone[0 ];
2621
+ XCTAssertEqual (tz.secondsFromGMT , currentTimeZone.offset .intValue + currentDSTOffset.offset .intValue );
2622
+ #endif // MTR_ENABLE_PROVISIONAL
2623
+ }
2624
+
2558
2625
- (void )test900_SubscribeAllAttributes
2559
2626
{
2560
2627
MTRBaseDevice * device = GetConnectedDevice ();
0 commit comments