@@ -904,48 +904,18 @@ time_zone::__get_info(sys_seconds __time) const {
904
904
std::__throw_runtime_error (" tzdb: corrupt db" );
905
905
}
906
906
907
- enum class __position {
908
- __beginning,
909
- __middle,
910
- __end,
911
- };
912
-
913
- // Determines the position of "__time" inside "__info".
914
- //
915
- // The code picks an arbitrary value to determine the "middle"
916
- // - Every time that is more than the threshold from a boundary, or
917
- // - Every value that is at the boundary sys_seconds::min() or
918
- // sys_seconds::max().
919
- //
920
- // If not in the middle, it returns __beginning or __end.
921
- [[nodiscard]] static __position __get_position (sys_seconds __time, const sys_info __info) {
922
- _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN (
923
- __time >= __info.begin && __time < __info.end , " A value outside the range's position can't be determined." );
924
-
925
- using _Tp = sys_seconds::rep;
926
- // Africa/Freetown has a 4 day "zone"
927
- // Africa/Freetown Fri Sep 1 00:59:59 1939 UT = Thu Aug 31 23:59:59 1939 -01 isdst=0 gmtoff=-3600
928
- // Africa/Freetown Fri Sep 1 01:00:00 1939 UT = Fri Sep 1 00:20:00 1939 -0040 isdst=1 gmtoff=-2400
929
- // Africa/Freetown Tue Sep 5 00:39:59 1939 UT = Mon Sep 4 23:59:59 1939 -0040 isdst=1 gmtoff=-2400
930
- // Africa/Freetown Tue Sep 5 00:40:00 1939 UT = Mon Sep 4 23:40:00 1939 -01 isdst=0 gmtoff=-3600
931
- //
932
- // Originally used a one week threshold, but due to this switched to 1 day.
933
- // This seems to work in practice.
934
- //
935
- // TODO TZDB Evaluate the proper threshold.
936
- constexpr _Tp __threshold = 24 * 3600 ;
937
-
938
- _Tp __upper = std::__add_sat (__info.begin .time_since_epoch ().count (), __threshold);
939
- if (__time >= __info.begin && __time.time_since_epoch ().count () < __upper)
940
- return __info.begin != sys_seconds::min () ? __position::__beginning : __position::__middle;
941
-
942
- _Tp __lower = std::__sub_sat (__info.end .time_since_epoch ().count (), __threshold);
943
- if (__time < __info.end && __time.time_since_epoch ().count () >= __lower)
944
- return __info.end != sys_seconds::max () ? __position::__end : __position::__middle;
907
+ // Is the "__local_time" present in "__first" and "__second". If so the
908
+ // local_info has an ambiguous result.
909
+ [[nodiscard]] static bool
910
+ __is_ambiguous (local_seconds __local_time, const sys_info& __first, const sys_info& __second) {
911
+ std::chrono::local_seconds __end_first{__first.end .time_since_epoch () + __first.offset };
912
+ std::chrono::local_seconds __begin_second{__second.begin .time_since_epoch () + __second.offset };
945
913
946
- return __position::__middle ;
914
+ return __local_time < __end_first && __local_time >= __begin_second ;
947
915
}
948
916
917
+ // Determines the result of the "__local_time". This expects the object
918
+ // "__first" to be earlier in time than "__second".
949
919
[[nodiscard]] static local_info
950
920
__get_info (local_seconds __local_time, const sys_info& __first, const sys_info& __second) {
951
921
std::chrono::local_seconds __end_first{__first.end .time_since_epoch () + __first.offset };
@@ -993,16 +963,16 @@ time_zone::__get_info(local_seconds __local_time) const {
993
963
* 2020.11.01 2021.04.01 2021.11.01
994
964
* offset +05 offset +05 offset +05
995
965
* save 0s save 1h save 0s
996
- * |-------------W ----------|
997
- * |----------W --------------|
966
+ * |------------// ----------|
967
+ * |---------// --------------|
998
968
* |-------------
999
969
* ~~ ^^
1000
970
*
1001
971
* These shifts can happen due to changes in the current time zone for a
1002
972
* location. For example, Indian/Kerguelen switched only once. In 1950 from an
1003
973
* offset of 0 hours to an offset of +05 hours.
1004
974
*
1005
- * During all these shifts the UTC time will have not gaps.
975
+ * During all these shifts the UTC time will not have gaps.
1006
976
*/
1007
977
1008
978
// The code needs to determine the system time for the local time. There is no
@@ -1012,8 +982,9 @@ time_zone::__get_info(local_seconds __local_time) const {
1012
982
sys_info __info = __get_info (__guess);
1013
983
1014
984
// At this point the offset can be used to determine an estimate for the local
1015
- // time. Before doing the determine the offset validate whether the local time
1016
- // is the range [chrono::local_seconds::min(), chrono::local_seconds::max()).
985
+ // time. Before doing that, determine the offset and validate whether the
986
+ // local time is the range [chrono::local_seconds::min(),
987
+ // chrono::local_seconds::max()).
1017
988
if (__local_seconds < 0s && __info.offset > 0s)
1018
989
if (__local_seconds - chrono::local_seconds::min ().time_since_epoch () < __info.offset )
1019
990
return {-1 , __info, {}};
@@ -1022,22 +993,23 @@ time_zone::__get_info(local_seconds __local_time) const {
1022
993
if (chrono::local_seconds::max ().time_since_epoch () - __local_seconds < -__info.offset )
1023
994
return {-2 , __info, {}};
1024
995
1025
- // Based on the information in the sys_info found the local time can be
996
+ // Based on the information found in the sys_info, the local time can be
1026
997
// converted to a system time. This resulting time can be in the following
1027
- // locations of the sys_info found :
998
+ // locations of the sys_info:
1028
999
//
1029
- // |----------W --------------|
1030
- // 1 2 3 4 5
1000
+ // |---------// --------------|
1001
+ // 1 2.1 2.2 2.3 5
1031
1002
//
1032
1003
// 1. The estimate is before the returned sys_info object.
1033
1004
// The result is either non-existent or unique in the previous sys_info.
1034
- // 2. The estimate is in the beginning of the returned sys_info object.
1035
- // The result is either unique or ambiguous with the previous sys_info.
1036
- // 3. The estimate is in the "middle" of the returned sys_info.
1037
- // The result is unique.
1038
- // 4. The result is at the end of the returned sys_info object.
1039
- // The result is either unique or ambiguous with the next sys_info.
1040
- // 5. The estimate is after the returned sys_info object.
1005
+ // 2. The estimate is in the sys_info object
1006
+ // - If the sys_info begin is not sys_seconds::min(), then it might be at
1007
+ // 2.1 and could be ambiguous with the previous or unique.
1008
+ // - If sys_info end is not sys_seconds::max(), then it might be at 2.3
1009
+ // and could be ambiguous with the next or unique.
1010
+ // - Else it is at 2.2 and always unique. This case happens when a
1011
+ // time zone has not transitions. For example, UTC or GMT+1.
1012
+ // 3. The estimate is after the returned sys_info object.
1041
1013
// The result is either non-existent or unique in the next sys_info.
1042
1014
//
1043
1015
// There is no specification where the "middle" starts. Similar issues can
@@ -1051,31 +1023,31 @@ time_zone::__get_info(local_seconds __local_time) const {
1051
1023
//
1052
1024
// However the local_info object only has 2 sys_info objects, so this option
1053
1025
// is not tested.
1054
- //
1055
- // The positions 2, 3, or 4 are determined by __get_position. This function
1056
- // also contains the definition of "middle".
1057
1026
1058
1027
sys_seconds __sys_time{__local_seconds - __info.offset };
1059
1028
if (__sys_time < __info.begin )
1060
1029
// Case 1 before __info
1061
1030
return chrono::__get_info (__local_time, __get_info (__info.begin - 1s), __info);
1062
1031
1063
1032
if (__sys_time >= __info.end )
1064
- // Case 5 after __info
1033
+ // Case 3 after __info
1065
1034
return chrono::__get_info (__local_time, __info, __get_info (__info.end ));
1066
1035
1067
- switch (__get_position (__sys_time, __info)) {
1068
- case __position::__beginning: // Case 2
1069
- return chrono::__get_info (__local_time, __get_info (__info.begin - 1s), __info);
1070
-
1071
- case __position::__middle: // Case 3
1072
- return {local_info::unique, __info, {}};
1073
-
1074
- case __position::__end: // Case 4
1075
- return chrono::__get_info (__local_time, __info, __get_info (__info.end ));
1036
+ // Case 2 in __info
1037
+ if (__info.begin != sys_seconds::min ()) {
1038
+ // Case 2.1 Not at the beginning, when not ambiguous the result should test
1039
+ // case 2.3.
1040
+ sys_info __prev = __get_info (__info.begin - 1s);
1041
+ if (__is_ambiguous (__local_time, __prev, __info))
1042
+ return {local_info::ambiguous, __prev, __info};
1076
1043
}
1077
1044
1078
- std::__libcpp_unreachable ();
1045
+ if (__info.end == sys_seconds::max ())
1046
+ // At the end so it's case 2.2
1047
+ return {local_info::unique, __info, sys_info{}};
1048
+
1049
+ // This tests case 2.2 or case 2.3.
1050
+ return chrono::__get_info (__local_time, __info, __get_info (__info.end ));
1079
1051
}
1080
1052
1081
1053
} // namespace chrono
0 commit comments