253 lines · cpp
1//===----------------------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9// UNSUPPORTED: c++03, c++11, c++14, c++1710// UNSUPPORTED: no-filesystem, no-localization, no-tzdb11 12// XFAIL: libcpp-has-no-experimental-tzdb13// XFAIL: availability-tzdb-missing14 15// <chrono>16 17// template<class Duration, class TimeZonePtr = const time_zone*>18// class zoned_time;19//20// zoned_time& operator=(const local_time<Duration>& st);21 22// TODO TZDB Investigate the issues in this test, this seems like23// a design issue of the class.24//25// [time.zone.zonedtime.members]/326// Effects: After assignment, get_local_time() == lt.27// This assignment has no effect on the return value of get_time_zone().28//29// The test cases describe the issues.30 31#include <cassert>32#include <chrono>33#include <concepts>34#include <type_traits>35 36#include "test_macros.h"37 38namespace cr = std::chrono;39 40// Tests unique conversions. To make sure the test is does not depend on changes41// in the database it uses a time zone with a fixed offset.42static void test_unique() {43 // common_type_t<duration, seconds> -> duration44 {45 using duration = cr::nanoseconds;46 using sys_time_point = cr::sys_time<duration>;47 using local_time_point = cr::local_time<duration>;48 using zoned_time = cr::zoned_time<duration>;49 zoned_time zt{"Etc/GMT+1", sys_time_point{duration{42}}};50 51 assert(zt.get_time_zone() == cr::locate_zone("Etc/GMT+1"));52 assert(zt.get_sys_time() == sys_time_point{duration{42}});53 assert(zt.get_local_time() == local_time_point{duration{42} - cr::hours{1}});54 55 std::same_as<zoned_time&> decltype(auto) result = zt = local_time_point{duration{99}};56 assert(&result == &zt);57 assert(zt.get_time_zone() == cr::locate_zone("Etc/GMT+1"));58 assert(zt.get_sys_time() == sys_time_point{duration{99} + cr::hours{1}});59 assert(zt.get_local_time() == local_time_point{duration{99}});60 }61 {62 using duration = cr::microseconds;63 using sys_time_point = cr::sys_time<duration>;64 using local_time_point = cr::local_time<duration>;65 using zoned_time = cr::zoned_time<duration>;66 zoned_time zt{"Etc/GMT+1", sys_time_point{duration{42}}};67 68 assert(zt.get_time_zone() == cr::locate_zone("Etc/GMT+1"));69 assert(zt.get_sys_time() == sys_time_point{duration{42}});70 assert(zt.get_local_time() == local_time_point{duration{42} - cr::hours{1}});71 72 std::same_as<zoned_time&> decltype(auto) result = zt = local_time_point{duration{99}};73 assert(&result == &zt);74 assert(zt.get_time_zone() == cr::locate_zone("Etc/GMT+1"));75 assert(zt.get_sys_time() == sys_time_point{duration{99} + cr::hours{1}});76 assert(zt.get_local_time() == local_time_point{duration{99}});77 }78 {79 using duration = cr::milliseconds;80 using sys_time_point = cr::sys_time<duration>;81 using local_time_point = cr::local_time<duration>;82 using zoned_time = cr::zoned_time<duration>;83 zoned_time zt{"Etc/GMT+1", sys_time_point{duration{42}}};84 85 assert(zt.get_time_zone() == cr::locate_zone("Etc/GMT+1"));86 assert(zt.get_sys_time() == sys_time_point{duration{42}});87 assert(zt.get_local_time() == local_time_point{duration{42} - cr::hours{1}});88 89 std::same_as<zoned_time&> decltype(auto) result = zt = local_time_point{duration{99}};90 assert(&result == &zt);91 assert(zt.get_time_zone() == cr::locate_zone("Etc/GMT+1"));92 assert(zt.get_sys_time() == sys_time_point{duration{99} + cr::hours{1}});93 assert(zt.get_local_time() == local_time_point{duration{99}});94 }95 // common_type_t<seconds, seconds> -> seconds96 {97 using duration = cr::seconds;98 using sys_time_point = cr::sys_time<duration>;99 using local_time_point = cr::local_time<duration>;100 using zoned_time = cr::zoned_time<duration>;101 zoned_time zt{"Etc/GMT+1", sys_time_point{duration{42}}};102 103 assert(zt.get_time_zone() == cr::locate_zone("Etc/GMT+1"));104 assert(zt.get_sys_time() == sys_time_point{duration{42}});105 assert(zt.get_local_time() == local_time_point{duration{42} - cr::hours{1}});106 107 std::same_as<zoned_time&> decltype(auto) result = zt = local_time_point{duration{99}};108 assert(&result == &zt);109 assert(zt.get_time_zone() == cr::locate_zone("Etc/GMT+1"));110 assert(zt.get_sys_time() == sys_time_point{duration{99} + cr::hours{1}});111 assert(zt.get_local_time() == local_time_point{duration{99}});112 }113 // common_type_t<duration, seconds> -> seconds114 {115 using duration = cr::days;116 using sys_time_point = cr::sys_time<duration>;117 using local_time_point = cr::local_time<duration>;118 using zoned_time = cr::zoned_time<duration>;119 zoned_time zt{"Etc/GMT+1", sys_time_point{duration{42}}};120 121 assert(zt.get_time_zone() == cr::locate_zone("Etc/GMT+1"));122 assert(zt.get_sys_time() == cr::sys_seconds{duration{42}});123 assert(zt.get_local_time() == cr::local_seconds{duration{42} - cr::hours{1}});124 125 std::same_as<zoned_time&> decltype(auto) result = zt = local_time_point{duration{99}};126 assert(&result == &zt);127 assert(zt.get_time_zone() == cr::locate_zone("Etc/GMT+1"));128 assert(zt.get_sys_time() == cr::sys_seconds{duration{99} + cr::hours{1}});129 assert(zt.get_local_time() == cr::local_seconds{duration{99}});130 }131 {132 using duration = cr::weeks;133 using sys_time_point = cr::sys_time<duration>;134 using local_time_point = cr::local_time<duration>;135 using zoned_time = cr::zoned_time<duration>;136 zoned_time zt{"Etc/GMT+1", sys_time_point{duration{42}}};137 138 assert(zt.get_time_zone() == cr::locate_zone("Etc/GMT+1"));139 assert(zt.get_sys_time() == cr::sys_seconds{duration{42}});140 assert(zt.get_local_time() == cr::local_seconds{duration{42} - cr::hours{1}});141 142 std::same_as<zoned_time&> decltype(auto) result = zt = local_time_point{duration{99}};143 assert(&result == &zt);144 assert(zt.get_time_zone() == cr::locate_zone("Etc/GMT+1"));145 assert(zt.get_sys_time() == cr::sys_seconds{duration{99} + cr::hours{1}});146 assert(zt.get_local_time() == cr::local_seconds{duration{99}});147 }148 /* This does not work; due to using __tp_ = __zone_->to_sys(__tp);149 * Here the ambiguous/non-existent exception can't stream months and years,150 * leading to a compilation error.151 {152 using duration = cr::months;153 using sys_time_point = cr::sys_time<duration>;154 using local_time_point = cr::local_time<duration>;155 using zoned_time = cr::zoned_time<duration>;156 zoned_time zt{"Etc/GMT+1", sys_time_point{duration{42}}};157 158 assert(zt.get_time_zone() == cr::locate_zone("Etc/GMT+1"));159 assert(zt.get_sys_time() == cr::sys_seconds{duration{42}});160 assert(zt.get_local_time() == cr::local_seconds{duration{42} - cr::hours{1}});161 162 std::same_as<zoned_time&> decltype(auto) result= zt = local_time_point{duration{99}};163 assert(&result == &zt);164 assert(zt.get_time_zone() == cr::locate_zone("Etc/GMT+1"));165 assert(zt.get_sys_time() == cr::sys_seconds{duration{99} + cr::hours{1}});166 assert(zt.get_local_time() == cr::local_seconds{duration{99}});167 } */168}169 170// Tests non-existent conversions.171static void test_nonexistent() {172#ifndef TEST_HAS_NO_EXCEPTIONS173 using namespace std::literals::chrono_literals;174 175 const cr::time_zone* tz = cr::locate_zone("Europe/Berlin");176 177 // Z Europe/Berlin 0:53:28 - LMT 1893 Ap178 // ...179 // 1 DE CE%sT 1980180 // 1 E CE%sT181 //182 // ...183 // R E 1981 ma - Mar lastSu 1u 1 S184 // R E 1996 ma - O lastSu 1u 0 -185 186 // Pick an historic date where it's well known what the time zone rules were.187 // This makes it unlikely updates to the database change these rules.188 cr::local_time<cr::seconds> time{(cr::sys_days{cr::March / 30 / 1986} + 2h + 30min).time_since_epoch()};189 190 using duration = cr::seconds;191 using zoned_time = cr::zoned_time<duration>;192 zoned_time zt{tz};193 194 bool thrown = false;195 try {196 std::same_as<zoned_time&> decltype(auto) result = zt = time;197 assert(&result == &zt);198 } catch (const cr::nonexistent_local_time&) {199 thrown = true;200 }201 // There is no system type that can represent the current local time. So the202 // assertion passes. The current implementation throws an exception too.203 assert(zt.get_local_time() != time);204 assert(thrown);205#endif // TEST_HAS_NO_EXCEPTIONS206}207 208// Tests ambiguous conversions.209static void test_ambiguous() {210#ifndef TEST_HAS_NO_EXCEPTIONS211 using namespace std::literals::chrono_literals;212 213 const cr::time_zone* tz = cr::locate_zone("Europe/Berlin");214 215 // Z Europe/Berlin 0:53:28 - LMT 1893 Ap216 // ...217 // 1 DE CE%sT 1980218 // 1 E CE%sT219 //220 // ...221 // R E 1981 ma - Mar lastSu 1u 1 S222 // R E 1996 ma - O lastSu 1u 0 -223 224 // Pick an historic date where it's well known what the time zone rules were.225 // This makes it unlikely updates to the database change these rules.226 cr::local_time<cr::seconds> time{(cr::sys_days{cr::September / 28 / 1986} + 2h + 30min).time_since_epoch()};227 228 using duration = cr::seconds;229 using zoned_time = cr::zoned_time<duration>;230 zoned_time zt{tz};231 232 bool thrown = false;233 try {234 std::same_as<zoned_time&> decltype(auto) result = zt = time;235 assert(&result == &zt);236 } catch (const cr::ambiguous_local_time&) {237 thrown = true;238 }239 // There is no system type that can represent the current local time. So the240 // assertion passes. The current implementation throws an exception too.241 assert(zt.get_local_time() != time);242 assert(thrown);243#endif // TEST_HAS_NO_EXCEPTIONS244}245 246int main(int, char**) {247 test_unique();248 test_nonexistent();249 test_ambiguous();250 251 return 0;252}253