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