From aecd5c6d23238f867b812a352068062f57716e0b Mon Sep 17 00:00:00 2001 From: zvonand Date: Tue, 9 Mar 2021 17:56:32 +0300 Subject: [PATCH] Added testflows tests for datetime64 extended range --- .../datetime64_extended_range/__init__.py | 0 .../datetime64_extended_range/common.py | 46 + .../configs/clickhouse/common.xml | 6 + .../configs/clickhouse/config.d/logs.xml | 17 + .../configs/clickhouse/config.d/ports.xml | 5 + .../configs/clickhouse/config.d/remote.xml | 107 + .../configs/clickhouse/config.d/ssl.xml | 17 + .../configs/clickhouse/config.d/storage.xml | 20 + .../configs/clickhouse/config.d/zookeeper.xml | 10 + .../configs/clickhouse/config.xml | 436 ++++ .../configs/clickhouse/ssl/dhparam.pem | 8 + .../configs/clickhouse/ssl/server.crt | 19 + .../configs/clickhouse/ssl/server.key | 28 + .../configs/clickhouse/users.xml | 133 + .../configs/clickhouse1/config.d/macros.xml | 8 + .../configs/clickhouse2/config.d/macros.xml | 8 + .../configs/clickhouse3/config.d/macros.xml | 8 + .../docker-compose/clickhouse-service.yml | 28 + .../docker-compose/docker-compose.yml | 63 + .../docker-compose/zookeeper-service.yml | 18 + .../datetime64_extended_range/regression.py | 95 + .../requirements/__init__.py | 1 + .../requirements/requirements.md | 837 ++++++ .../requirements/requirements.py | 2313 +++++++++++++++++ .../datetime64_extended_range/test.log | Bin 0 -> 56172 bytes .../datetime64_extended_range/tests/common.py | 179 ++ .../tests/date_time_functions.py | 1530 +++++++++++ .../tests/generic.py | 177 ++ .../tests/non_existent_time.py | 164 ++ .../tests/reference_times.py | 38 + .../tests/type_conversion.py | 479 ++++ tests/testflows/regression.py | 1 + 32 files changed, 6799 insertions(+) create mode 100644 tests/testflows/datetime64_extended_range/__init__.py create mode 100644 tests/testflows/datetime64_extended_range/common.py create mode 100644 tests/testflows/datetime64_extended_range/configs/clickhouse/common.xml create mode 100644 tests/testflows/datetime64_extended_range/configs/clickhouse/config.d/logs.xml create mode 100644 tests/testflows/datetime64_extended_range/configs/clickhouse/config.d/ports.xml create mode 100644 tests/testflows/datetime64_extended_range/configs/clickhouse/config.d/remote.xml create mode 100644 tests/testflows/datetime64_extended_range/configs/clickhouse/config.d/ssl.xml create mode 100644 tests/testflows/datetime64_extended_range/configs/clickhouse/config.d/storage.xml create mode 100644 tests/testflows/datetime64_extended_range/configs/clickhouse/config.d/zookeeper.xml create mode 100644 tests/testflows/datetime64_extended_range/configs/clickhouse/config.xml create mode 100644 tests/testflows/datetime64_extended_range/configs/clickhouse/ssl/dhparam.pem create mode 100644 tests/testflows/datetime64_extended_range/configs/clickhouse/ssl/server.crt create mode 100644 tests/testflows/datetime64_extended_range/configs/clickhouse/ssl/server.key create mode 100644 tests/testflows/datetime64_extended_range/configs/clickhouse/users.xml create mode 100644 tests/testflows/datetime64_extended_range/configs/clickhouse1/config.d/macros.xml create mode 100644 tests/testflows/datetime64_extended_range/configs/clickhouse2/config.d/macros.xml create mode 100644 tests/testflows/datetime64_extended_range/configs/clickhouse3/config.d/macros.xml create mode 100644 tests/testflows/datetime64_extended_range/docker-compose/clickhouse-service.yml create mode 100644 tests/testflows/datetime64_extended_range/docker-compose/docker-compose.yml create mode 100644 tests/testflows/datetime64_extended_range/docker-compose/zookeeper-service.yml create mode 100755 tests/testflows/datetime64_extended_range/regression.py create mode 100644 tests/testflows/datetime64_extended_range/requirements/__init__.py create mode 100644 tests/testflows/datetime64_extended_range/requirements/requirements.md create mode 100644 tests/testflows/datetime64_extended_range/requirements/requirements.py create mode 100644 tests/testflows/datetime64_extended_range/test.log create mode 100644 tests/testflows/datetime64_extended_range/tests/common.py create mode 100644 tests/testflows/datetime64_extended_range/tests/date_time_functions.py create mode 100644 tests/testflows/datetime64_extended_range/tests/generic.py create mode 100644 tests/testflows/datetime64_extended_range/tests/non_existent_time.py create mode 100644 tests/testflows/datetime64_extended_range/tests/reference_times.py create mode 100644 tests/testflows/datetime64_extended_range/tests/type_conversion.py diff --git a/tests/testflows/datetime64_extended_range/__init__.py b/tests/testflows/datetime64_extended_range/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/testflows/datetime64_extended_range/common.py b/tests/testflows/datetime64_extended_range/common.py new file mode 100644 index 00000000000..f441cd2b469 --- /dev/null +++ b/tests/testflows/datetime64_extended_range/common.py @@ -0,0 +1,46 @@ +from multiprocessing.dummy import Pool + +from testflows.core import * + +def join(tasks, test=None): + """Join all parallel tests. + """ + exc = None + + if test is None: + test = current() + + for task in tasks: + try: + task.get() + except Exception as e: + exc = e + + if exc: + raise exc + +def start(pool, tasks, scenario, kwargs=None, test=None): + """Start parallel test. + """ + if test is None: + test = current() + if kwargs is None: + kwargs = {} + + task = pool.apply_async(scenario, [], kwargs) + tasks.append(task) + return task + +def run_scenario(pool, tasks, scenario, kwargs=None): + """Run scenario in parallel if parallel flag is set + in the context. + """ + if kwargs is None: + kwargs = {} + + if current().context.parallel: + start(pool, tasks, scenario, kwargs) + else: + scenario(**kwargs) + + diff --git a/tests/testflows/datetime64_extended_range/configs/clickhouse/common.xml b/tests/testflows/datetime64_extended_range/configs/clickhouse/common.xml new file mode 100644 index 00000000000..df952b28c82 --- /dev/null +++ b/tests/testflows/datetime64_extended_range/configs/clickhouse/common.xml @@ -0,0 +1,6 @@ + + Europe/Moscow + 0.0.0.0 + /var/lib/clickhouse/ + /var/lib/clickhouse/tmp/ + diff --git a/tests/testflows/datetime64_extended_range/configs/clickhouse/config.d/logs.xml b/tests/testflows/datetime64_extended_range/configs/clickhouse/config.d/logs.xml new file mode 100644 index 00000000000..bdf1bbc11c1 --- /dev/null +++ b/tests/testflows/datetime64_extended_range/configs/clickhouse/config.d/logs.xml @@ -0,0 +1,17 @@ + + 3 + + trace + /var/log/clickhouse-server/log.log + /var/log/clickhouse-server/log.err.log + 1000M + 10 + /var/log/clickhouse-server/stderr.log + /var/log/clickhouse-server/stdout.log + + + system + part_log
+ 500 +
+
diff --git a/tests/testflows/datetime64_extended_range/configs/clickhouse/config.d/ports.xml b/tests/testflows/datetime64_extended_range/configs/clickhouse/config.d/ports.xml new file mode 100644 index 00000000000..fbc6cea74c0 --- /dev/null +++ b/tests/testflows/datetime64_extended_range/configs/clickhouse/config.d/ports.xml @@ -0,0 +1,5 @@ + + + 8443 + 9440 + \ No newline at end of file diff --git a/tests/testflows/datetime64_extended_range/configs/clickhouse/config.d/remote.xml b/tests/testflows/datetime64_extended_range/configs/clickhouse/config.d/remote.xml new file mode 100644 index 00000000000..51be2a6e8e3 --- /dev/null +++ b/tests/testflows/datetime64_extended_range/configs/clickhouse/config.d/remote.xml @@ -0,0 +1,107 @@ + + + + + + true + + clickhouse1 + 9000 + + + clickhouse2 + 9000 + + + clickhouse3 + 9000 + + + + + + + true + + clickhouse1 + 9440 + 1 + + + clickhouse2 + 9440 + 1 + + + clickhouse3 + 9440 + 1 + + + + + + + clickhouse1 + 9000 + + + + + clickhouse2 + 9000 + + + + + clickhouse3 + 9000 + + + + + + + clickhouse1 + 9440 + 1 + + + + + clickhouse2 + 9440 + 1 + + + + + clickhouse3 + 9440 + 1 + + + + + diff --git a/tests/testflows/datetime64_extended_range/configs/clickhouse/config.d/ssl.xml b/tests/testflows/datetime64_extended_range/configs/clickhouse/config.d/ssl.xml new file mode 100644 index 00000000000..ca65ffd5e04 --- /dev/null +++ b/tests/testflows/datetime64_extended_range/configs/clickhouse/config.d/ssl.xml @@ -0,0 +1,17 @@ + + + + /etc/clickhouse-server/ssl/server.crt + /etc/clickhouse-server/ssl/server.key + none + true + + + true + none + + AcceptCertificateHandler + + + + diff --git a/tests/testflows/datetime64_extended_range/configs/clickhouse/config.d/storage.xml b/tests/testflows/datetime64_extended_range/configs/clickhouse/config.d/storage.xml new file mode 100644 index 00000000000..618fd6b6d24 --- /dev/null +++ b/tests/testflows/datetime64_extended_range/configs/clickhouse/config.d/storage.xml @@ -0,0 +1,20 @@ + + + + + + 1024 + + + + + + + default + + + + + + + diff --git a/tests/testflows/datetime64_extended_range/configs/clickhouse/config.d/zookeeper.xml b/tests/testflows/datetime64_extended_range/configs/clickhouse/config.d/zookeeper.xml new file mode 100644 index 00000000000..96270e7b645 --- /dev/null +++ b/tests/testflows/datetime64_extended_range/configs/clickhouse/config.d/zookeeper.xml @@ -0,0 +1,10 @@ + + + + + zookeeper + 2181 + + 15000 + + diff --git a/tests/testflows/datetime64_extended_range/configs/clickhouse/config.xml b/tests/testflows/datetime64_extended_range/configs/clickhouse/config.xml new file mode 100644 index 00000000000..d34d2c35253 --- /dev/null +++ b/tests/testflows/datetime64_extended_range/configs/clickhouse/config.xml @@ -0,0 +1,436 @@ + + + + + + trace + /var/log/clickhouse-server/clickhouse-server.log + /var/log/clickhouse-server/clickhouse-server.err.log + 1000M + 10 + + + + 8123 + 9000 + + + + + + + + + /etc/clickhouse-server/server.crt + /etc/clickhouse-server/server.key + + /etc/clickhouse-server/dhparam.pem + none + true + true + sslv2,sslv3 + true + + + + true + true + sslv2,sslv3 + true + + + + RejectCertificateHandler + + + + + + + + + 9009 + + + + + + + + + + + + + + + + + + + + 4096 + 3 + + + 100 + + + + + + 8589934592 + + + 5368709120 + + + + /var/lib/clickhouse/ + + + /var/lib/clickhouse/tmp/ + + + /var/lib/clickhouse/user_files/ + + + /var/lib/clickhouse/access/ + + + users.xml + + + default + + + + + + default + + + + + + + + + false + + + + + + + + localhost + 9000 + + + + + + + localhost + 9000 + + + + + localhost + 9000 + + + + + + + localhost + 9440 + 1 + + + + + + + localhost + 9000 + + + + + localhost + 1 + + + + + + + + + + + + + + + + + 3600 + + + + 3600 + + + 60 + + + + + + + + + + system + query_log
+ + toYYYYMM(event_date) + + 7500 +
+ + + + system + trace_log
+ + toYYYYMM(event_date) + 7500 +
+ + + + system + query_thread_log
+ toYYYYMM(event_date) + 7500 +
+ + + + + + + + + + + + + + + + *_dictionary.xml + + + + + + + + + + /clickhouse/task_queue/ddl + + + + + + + + + + + + + + + + click_cost + any + + 0 + 3600 + + + 86400 + 60 + + + + max + + 0 + 60 + + + 3600 + 300 + + + 86400 + 3600 + + + + + + /var/lib/clickhouse/format_schemas/ + + + +
diff --git a/tests/testflows/datetime64_extended_range/configs/clickhouse/ssl/dhparam.pem b/tests/testflows/datetime64_extended_range/configs/clickhouse/ssl/dhparam.pem new file mode 100644 index 00000000000..2e6cee0798d --- /dev/null +++ b/tests/testflows/datetime64_extended_range/configs/clickhouse/ssl/dhparam.pem @@ -0,0 +1,8 @@ +-----BEGIN DH PARAMETERS----- +MIIBCAKCAQEAua92DDli13gJ+//ZXyGaggjIuidqB0crXfhUlsrBk9BV1hH3i7fR +XGP9rUdk2ubnB3k2ejBStL5oBrkHm9SzUFSQHqfDjLZjKoUpOEmuDc4cHvX1XTR5 +Pr1vf5cd0yEncJWG5W4zyUB8k++SUdL2qaeslSs+f491HBLDYn/h8zCgRbBvxhxb +9qeho1xcbnWeqkN6Kc9bgGozA16P9NLuuLttNnOblkH+lMBf42BSne/TWt3AlGZf +slKmmZcySUhF8aKfJnLKbkBCFqOtFRh8zBA9a7g+BT/lSANATCDPaAk1YVih2EKb +dpc3briTDbRsiqg2JKMI7+VdULY9bh3EawIBAg== +-----END DH PARAMETERS----- diff --git a/tests/testflows/datetime64_extended_range/configs/clickhouse/ssl/server.crt b/tests/testflows/datetime64_extended_range/configs/clickhouse/ssl/server.crt new file mode 100644 index 00000000000..7ade2d96273 --- /dev/null +++ b/tests/testflows/datetime64_extended_range/configs/clickhouse/ssl/server.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIC/TCCAeWgAwIBAgIJANjx1QSR77HBMA0GCSqGSIb3DQEBCwUAMBQxEjAQBgNV +BAMMCWxvY2FsaG9zdDAgFw0xODA3MzAxODE2MDhaGA8yMjkyMDUxNDE4MTYwOFow +FDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEAs9uSo6lJG8o8pw0fbVGVu0tPOljSWcVSXH9uiJBwlZLQnhN4SFSFohfI +4K8U1tBDTnxPLUo/V1K9yzoLiRDGMkwVj6+4+hE2udS2ePTQv5oaMeJ9wrs+5c9T +4pOtlq3pLAdm04ZMB1nbrEysceVudHRkQbGHzHp6VG29Fw7Ga6YpqyHQihRmEkTU +7UCYNA+Vk7aDPdMS/khweyTpXYZimaK9f0ECU3/VOeG3fH6Sp2X6FN4tUj/aFXEj +sRmU5G2TlYiSIUMF2JPdhSihfk1hJVALrHPTU38SOL+GyyBRWdNcrIwVwbpvsvPg +pryMSNxnpr0AK0dFhjwnupIv5hJIOQIDAQABo1AwTjAdBgNVHQ4EFgQUjPLb3uYC +kcamyZHK4/EV8jAP0wQwHwYDVR0jBBgwFoAUjPLb3uYCkcamyZHK4/EV8jAP0wQw +DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAM/ocuDvfPus/KpMVD51j +4IdlU8R0vmnYLQ+ygzOAo7+hUWP5j0yvq4ILWNmQX6HNvUggCgFv9bjwDFhb/5Vr +85ieWfTd9+LTjrOzTw4avdGwpX9G+6jJJSSq15tw5ElOIFb/qNA9O4dBiu8vn03C +L/zRSXrARhSqTW5w/tZkUcSTT+M5h28+Lgn9ysx4Ff5vi44LJ1NnrbJbEAIYsAAD ++UA+4MBFKx1r6hHINULev8+lCfkpwIaeS8RL+op4fr6kQPxnULw8wT8gkuc8I4+L +P9gg/xDHB44T3ADGZ5Ib6O0DJaNiToO6rnoaaxs0KkotbvDWvRoxEytSbXKoYjYp +0g== +-----END CERTIFICATE----- diff --git a/tests/testflows/datetime64_extended_range/configs/clickhouse/ssl/server.key b/tests/testflows/datetime64_extended_range/configs/clickhouse/ssl/server.key new file mode 100644 index 00000000000..f0fb61ac443 --- /dev/null +++ b/tests/testflows/datetime64_extended_range/configs/clickhouse/ssl/server.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCz25KjqUkbyjyn +DR9tUZW7S086WNJZxVJcf26IkHCVktCeE3hIVIWiF8jgrxTW0ENOfE8tSj9XUr3L +OguJEMYyTBWPr7j6ETa51LZ49NC/mhox4n3Cuz7lz1Pik62WreksB2bThkwHWdus +TKxx5W50dGRBsYfMenpUbb0XDsZrpimrIdCKFGYSRNTtQJg0D5WTtoM90xL+SHB7 +JOldhmKZor1/QQJTf9U54bd8fpKnZfoU3i1SP9oVcSOxGZTkbZOViJIhQwXYk92F +KKF+TWElUAusc9NTfxI4v4bLIFFZ01ysjBXBum+y8+CmvIxI3GemvQArR0WGPCe6 +ki/mEkg5AgMBAAECggEATrbIBIxwDJOD2/BoUqWkDCY3dGevF8697vFuZKIiQ7PP +TX9j4vPq0DfsmDjHvAPFkTHiTQXzlroFik3LAp+uvhCCVzImmHq0IrwvZ9xtB43f +7Pkc5P6h1l3Ybo8HJ6zRIY3TuLtLxuPSuiOMTQSGRL0zq3SQ5DKuGwkz+kVjHXUN +MR2TECFwMHKQ5VLrC+7PMpsJYyOMlDAWhRfUalxC55xOXTpaN8TxNnwQ8K2ISVY5 +212Jz/a4hn4LdwxSz3Tiu95PN072K87HLWx3EdT6vW4Ge5P/A3y+smIuNAlanMnu +plHBRtpATLiTxZt/n6npyrfQVbYjSH7KWhB8hBHtaQKBgQDh9Cq1c/KtqDtE0Ccr +/r9tZNTUwBE6VP+3OJeKdEdtsfuxjOCkS1oAjgBJiSDOiWPh1DdoDeVZjPKq6pIu +Mq12OE3Doa8znfCXGbkSzEKOb2unKZMJxzrz99kXt40W5DtrqKPNb24CNqTiY8Aa +CjtcX+3weat82VRXvph6U8ltMwKBgQDLxjiQQzNoY7qvg7CwJCjf9qq8jmLK766g +1FHXopqS+dTxDLM8eJSRrpmxGWJvNeNc1uPhsKsKgotqAMdBUQTf7rSTbt4MyoH5 +bUcRLtr+0QTK9hDWMOOvleqNXha68vATkohWYfCueNsC60qD44o8RZAS6UNy3ENq +cM1cxqe84wKBgQDKkHutWnooJtajlTxY27O/nZKT/HA1bDgniMuKaz4R4Gr1PIez +on3YW3V0d0P7BP6PWRIm7bY79vkiMtLEKdiKUGWeyZdo3eHvhDb/3DCawtau8L2K +GZsHVp2//mS1Lfz7Qh8/L/NedqCQ+L4iWiPnZ3THjjwn3CoZ05ucpvrAMwKBgB54 +nay039MUVq44Owub3KDg+dcIU62U+cAC/9oG7qZbxYPmKkc4oL7IJSNecGHA5SbU +2268RFdl/gLz6tfRjbEOuOHzCjFPdvAdbysanpTMHLNc6FefJ+zxtgk9sJh0C4Jh +vxFrw9nTKKzfEl12gQ1SOaEaUIO0fEBGbe8ZpauRAoGAMAlGV+2/K4ebvAJKOVTa +dKAzQ+TD2SJmeR1HZmKDYddNqwtZlzg3v4ZhCk4eaUmGeC1Bdh8MDuB3QQvXz4Dr +vOIP4UVaOr+uM+7TgAgVnP4/K6IeJGzUDhX93pmpWhODfdu/oojEKVcpCojmEmS1 +KCBtmIrQLqzMpnBpLNuSY+Q= +-----END PRIVATE KEY----- diff --git a/tests/testflows/datetime64_extended_range/configs/clickhouse/users.xml b/tests/testflows/datetime64_extended_range/configs/clickhouse/users.xml new file mode 100644 index 00000000000..86b2cd9e1e3 --- /dev/null +++ b/tests/testflows/datetime64_extended_range/configs/clickhouse/users.xml @@ -0,0 +1,133 @@ + + + + + + + + 10000000000 + + + 0 + + + random + + + + + 1 + + + + + + + + + + + + + ::/0 + + + + default + + + default + + + 1 + + + + + + + + + + + + + + + + + 3600 + + + 0 + 0 + 0 + 0 + 0 + + + + diff --git a/tests/testflows/datetime64_extended_range/configs/clickhouse1/config.d/macros.xml b/tests/testflows/datetime64_extended_range/configs/clickhouse1/config.d/macros.xml new file mode 100644 index 00000000000..6cdcc1b440c --- /dev/null +++ b/tests/testflows/datetime64_extended_range/configs/clickhouse1/config.d/macros.xml @@ -0,0 +1,8 @@ + + + + clickhouse1 + 01 + 01 + + diff --git a/tests/testflows/datetime64_extended_range/configs/clickhouse2/config.d/macros.xml b/tests/testflows/datetime64_extended_range/configs/clickhouse2/config.d/macros.xml new file mode 100644 index 00000000000..a114a9ce4ab --- /dev/null +++ b/tests/testflows/datetime64_extended_range/configs/clickhouse2/config.d/macros.xml @@ -0,0 +1,8 @@ + + + + clickhouse2 + 01 + 02 + + diff --git a/tests/testflows/datetime64_extended_range/configs/clickhouse3/config.d/macros.xml b/tests/testflows/datetime64_extended_range/configs/clickhouse3/config.d/macros.xml new file mode 100644 index 00000000000..904a27b0172 --- /dev/null +++ b/tests/testflows/datetime64_extended_range/configs/clickhouse3/config.d/macros.xml @@ -0,0 +1,8 @@ + + + + clickhouse3 + 01 + 03 + + diff --git a/tests/testflows/datetime64_extended_range/docker-compose/clickhouse-service.yml b/tests/testflows/datetime64_extended_range/docker-compose/clickhouse-service.yml new file mode 100644 index 00000000000..9787b37abbb --- /dev/null +++ b/tests/testflows/datetime64_extended_range/docker-compose/clickhouse-service.yml @@ -0,0 +1,28 @@ +version: '2.3' + +services: + clickhouse: + image: yandex/clickhouse-integration-test + expose: + - "9000" + - "9009" + - "8123" + volumes: + - "${CLICKHOUSE_TESTS_DIR}/configs/clickhouse/config.d:/etc/clickhouse-server/config.d" + - "${CLICKHOUSE_TESTS_DIR}/configs/clickhouse/users.d/:/etc/clickhouse-server/users.d" + - "${CLICKHOUSE_TESTS_DIR}/configs/clickhouse/ssl:/etc/clickhouse-server/ssl" + - "${CLICKHOUSE_TESTS_DIR}/configs/clickhouse/config.xml:/etc/clickhouse-server/config.xml" + - "${CLICKHOUSE_TESTS_DIR}/configs/clickhouse/users.xml:/etc/clickhouse-server/users.xml" + - "${CLICKHOUSE_TESTS_SERVER_BIN_PATH:-/usr/bin/clickhouse}:/usr/bin/clickhouse" + - "${CLICKHOUSE_TESTS_ODBC_BRIDGE_BIN_PATH:-/usr/bin/clickhouse-odbc-bridge}:/usr/bin/clickhouse-odbc-bridge" + entrypoint: bash -c "clickhouse server --config-file=/etc/clickhouse-server/config.xml --log-file=/var/log/clickhouse-server/clickhouse-server.log --errorlog-file=/var/log/clickhouse-server/clickhouse-server.err.log" + healthcheck: + test: clickhouse client --query='select 1' + interval: 3s + timeout: 2s + retries: 40 + start_period: 2s + cap_add: + - SYS_PTRACE + security_opt: + - label:disable diff --git a/tests/testflows/datetime64_extended_range/docker-compose/docker-compose.yml b/tests/testflows/datetime64_extended_range/docker-compose/docker-compose.yml new file mode 100644 index 00000000000..efd60180800 --- /dev/null +++ b/tests/testflows/datetime64_extended_range/docker-compose/docker-compose.yml @@ -0,0 +1,63 @@ +version: '2.3' + +services: + zookeeper: + extends: + file: zookeeper-service.yml + service: zookeeper + + clickhouse1: + extends: + file: clickhouse-service.yml + service: clickhouse + hostname: clickhouse1 + volumes: + - "${CLICKHOUSE_TESTS_DIR}/_instances/clickhouse1/database/:/var/lib/clickhouse/" + - "${CLICKHOUSE_TESTS_DIR}/_instances/clickhouse1/logs/:/var/log/clickhouse-server/" + - "${CLICKHOUSE_TESTS_DIR}/configs/clickhouse1/config.d:/etc/clickhouse-server/config.d" + - "${CLICKHOUSE_TESTS_DIR}/configs/clickhouse1/users.d:/etc/clickhouse-server/users.d" + depends_on: + zookeeper: + condition: service_healthy + + clickhouse2: + extends: + file: clickhouse-service.yml + service: clickhouse + hostname: clickhouse2 + volumes: + - "${CLICKHOUSE_TESTS_DIR}/_instances/clickhouse2/database/:/var/lib/clickhouse/" + - "${CLICKHOUSE_TESTS_DIR}/_instances/clickhouse2/logs/:/var/log/clickhouse-server/" + - "${CLICKHOUSE_TESTS_DIR}/configs/clickhouse2/config.d:/etc/clickhouse-server/config.d" + - "${CLICKHOUSE_TESTS_DIR}/configs/clickhouse2/users.d:/etc/clickhouse-server/users.d" + depends_on: + zookeeper: + condition: service_healthy + + clickhouse3: + extends: + file: clickhouse-service.yml + service: clickhouse + hostname: clickhouse3 + volumes: + - "${CLICKHOUSE_TESTS_DIR}/_instances/clickhouse3/database/:/var/lib/clickhouse/" + - "${CLICKHOUSE_TESTS_DIR}/_instances/clickhouse3/logs/:/var/log/clickhouse-server/" + - "${CLICKHOUSE_TESTS_DIR}/configs/clickhouse3/config.d:/etc/clickhouse-server/config.d" + - "${CLICKHOUSE_TESTS_DIR}/configs/clickhouse3/users.d:/etc/clickhouse-server/users.d" + depends_on: + zookeeper: + condition: service_healthy + + # dummy service which does nothing, but allows to postpone + # 'docker-compose up -d' till all dependecies will go healthy + all_services_ready: + image: hello-world + depends_on: + clickhouse1: + condition: service_healthy + clickhouse2: + condition: service_healthy + clickhouse3: + condition: service_healthy + zookeeper: + condition: service_healthy diff --git a/tests/testflows/datetime64_extended_range/docker-compose/zookeeper-service.yml b/tests/testflows/datetime64_extended_range/docker-compose/zookeeper-service.yml new file mode 100644 index 00000000000..f3df33358be --- /dev/null +++ b/tests/testflows/datetime64_extended_range/docker-compose/zookeeper-service.yml @@ -0,0 +1,18 @@ +version: '2.3' + +services: + zookeeper: + image: zookeeper:3.4.12 + expose: + - "2181" + environment: + ZOO_TICK_TIME: 500 + ZOO_MY_ID: 1 + healthcheck: + test: echo stat | nc localhost 2181 + interval: 3s + timeout: 2s + retries: 5 + start_period: 2s + security_opt: + - label:disable diff --git a/tests/testflows/datetime64_extended_range/regression.py b/tests/testflows/datetime64_extended_range/regression.py new file mode 100755 index 00000000000..7daf25ea751 --- /dev/null +++ b/tests/testflows/datetime64_extended_range/regression.py @@ -0,0 +1,95 @@ +#!/usr/bin/env python3 +# Copyright 2020, Altinity LTD. All Rights Reserved. +# +# All information contained herein is, and remains the property +# of Altinity LTD. Any dissemination of this information or +# reproduction of this material is strictly forbidden unless +# prior written permission is obtained from Altinity LTD. +# +import sys +from testflows.core import * + +append_path(sys.path, "..") + +from helpers.cluster import Cluster +from helpers.argparser import argparser +from datetime64_extended_range.requirements import * +from datetime64_extended_range.common import * + +# cross-outs +# https://github.com/ClickHouse/ClickHouse/issues/15486 : wrong seconds value prior to 1920 + +xfails = { + "date time funcs/to year/:": [(Fail, "https://github.com/ClickHouse/ClickHouse/issues/15784")], + "date time funcs/to time zone/:": [(Fail, "https://github.com/ClickHouse/ClickHouse/issues/15784")], + "generic/timezone local below normal range/:": [(Fail, "https://github.com/ClickHouse/ClickHouse/issues/16222")], + "generic/timezone local below extended range/:": [(Fail, "https://github.com/ClickHouse/ClickHouse/issues/15486")], + "generic/timezones support*:": [(Fail, "https://github.com/ClickHouse/ClickHouse/issues/15486")], + "date time funcs/to quarter/:": [(Fail, "https://github.com/ClickHouse/ClickHouse/issues/15784")], + "date time funcs/to month/:": [(Fail, "https://github.com/ClickHouse/ClickHouse/issues/15784")], + "date time funcs/to unix timestamp": [(Fail, "https://github.com/ClickHouse/ClickHouse/issues/15784")], + "date time funcs/to day of month": [(Fail, "https://github.com/ClickHouse/ClickHouse/issues/15784")], + "date time funcs/to day of week": [(Fail, "https://github.com/ClickHouse/ClickHouse/issues/15784")], + "date time funcs/to day of year": [(Fail, "https://github.com/ClickHouse/ClickHouse/issues/15784")], + "date time funcs/to hour": [(Fail, "https://github.com/ClickHouse/ClickHouse/issues/15784")], + "date time funcs/to minute": [(Fail, "https://github.com/ClickHouse/ClickHouse/issues/15784")], + "date time funcs/to second": [(Fail, "https://github.com/ClickHouse/ClickHouse/issues/15784")], + "date time funcs/to year": [(Fail, "https://github.com/ClickHouse/ClickHouse/issues/15784")], + "date time funcs/to iso year": [(Fail, "https://github.com/ClickHouse/ClickHouse/issues/15784")], + "date time funcs/to iso week": [(Fail, "https://github.com/ClickHouse/ClickHouse/issues/15784")], + "date time funcs/to monday": [(Fail, "https://github.com/ClickHouse/ClickHouse/issues/15784")], + "date time funcs/to relative :": [(Fail, "https://github.com/ClickHouse/ClickHouse/issues/15784")], + "date time funcs/to time": [(Fail, "https://github.com/ClickHouse/ClickHouse/issues/15784")], + "date time funcs/to start of :": [(Fail, "https://github.com/ClickHouse/ClickHouse/issues/15784")], + "date time funcs/to yyyy:": [(Fail, "https://github.com/ClickHouse/ClickHouse/issues/15784")], + "date time funcs/time slot": [(Fail, "https://github.com/ClickHouse/ClickHouse/issues/15784")], + "date time funcs/add :": [(Fail, "https://github.com/ClickHouse/ClickHouse/issues/15486")], + "date time funcs/subtract :": [(Fail, "https://github.com/ClickHouse/ClickHouse/issues/15486")], + "date time funcs/to week": [(Fail, "https://github.com/ClickHouse/ClickHouse/issues/15784")], + "date time funcs/to year week": [(Fail, "https://github.com/ClickHouse/ClickHouse/issues/15784")], + "date time funcs/format date time": [(Fail, "https://github.com/ClickHouse/ClickHouse/issues/15784")], + "date time funcs/date diff/:": [(Fail, "https://github.com/ClickHouse/ClickHouse/issues/16260")], + "date time funcs/time slots*": [(Fail, "https://github.com/ClickHouse/ClickHouse/issues/16260")], + "type conversion/to datetime64": [(Fail, "https://github.com/ClickHouse/ClickHouse/issues/15486")], + "type conversion/to uint 8 16 32 64 256*": [(Fail, "https://github.com/ClickHouse/ClickHouse/issues/16581")], + "type conversion/to int 8 16 32 64 128 256*": [(Fail, "https://github.com/ClickHouse/ClickHouse/issues/16581")], + "type conversion/from unix timestamp64*": [(Fail, "https://github.com/ClickHouse/ClickHouse/issues/15486")], + "type conversion/to unix timestamp64*": [(Fail, "https://github.com/ClickHouse/ClickHouse/issues/15486")], + "type conversion/to string*": [(Fail, "https://github.com/ClickHouse/ClickHouse/issues/15486")], + "type conversion/to datetime64 from string missing time*": [(Fail, "https://github.com/ClickHouse/ClickHouse/issues/17080")], + "non existent time/dst time zone switch*": [(Fail, "https://github.com/ClickHouse/ClickHouse/issues/16924")], + "non existent time/leap seconds*": [(Fail, "https://github.com/ClickHouse/ClickHouse/issues/17079")], + "reference times": [(Fail, "https://github.com/ClickHouse/ClickHouse/issues/16924")] +} + + +@TestModule +@Name("datetime64 extended range") +@ArgumentParser(argparser) +@Specifications( + QA_SRS010_ClickHouse_DateTime64_Extended_Range +) +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange("1.0"), +) +@XFails(xfails) +def regression(self, local, clickhouse_binary_path, parallel=False, stress=False): + """ClickHouse DateTime64 Extended Range regression module. + """ + nodes = { + "clickhouse": ("clickhouse1", "clickhouse2", "clickhouse3"), + } + + with Cluster(local, clickhouse_binary_path, nodes=nodes) as cluster: + self.context.cluster = cluster + self.context.parallel = parallel + self.context.stress = stress + + Scenario(run=load("datetime64_extended_range.tests.generic", "generic"), flags=TE) + Scenario(run=load("datetime64_extended_range.tests.non_existent_time", "feature"), flags=TE) + Scenario(run=load("datetime64_extended_range.tests.reference_times", "reference_times"), flags=TE) + Scenario(run=load("datetime64_extended_range.tests.date_time_functions", "date_time_funcs"), flags=TE) + Scenario(run=load("datetime64_extended_range.tests.type_conversion", "type_conversion"), flags=TE) + +if main(): + regression() diff --git a/tests/testflows/datetime64_extended_range/requirements/__init__.py b/tests/testflows/datetime64_extended_range/requirements/__init__.py new file mode 100644 index 00000000000..02f7d430154 --- /dev/null +++ b/tests/testflows/datetime64_extended_range/requirements/__init__.py @@ -0,0 +1 @@ +from .requirements import * diff --git a/tests/testflows/datetime64_extended_range/requirements/requirements.md b/tests/testflows/datetime64_extended_range/requirements/requirements.md new file mode 100644 index 00000000000..b44c1fb529f --- /dev/null +++ b/tests/testflows/datetime64_extended_range/requirements/requirements.md @@ -0,0 +1,837 @@ +# QA-SRS010 ClickHouse DateTime64 Extended Range +# Software Requirements Specification + +(c) 2020 Altinity LTD. All Rights Reserved. + +**Document status:** Confidential + +**Author:** vzakaznikov, zvonand + +**Date:** August 10, 2020 + +## Approval + +**Status:** - + +**Version:** - + +**Approved by:** - + +**Date:** - + +## Table of Contents + +* 1 [Revision History](#revision-history) +* 2 [Introduction](#introduction) +* 3 [Terminology](#terminology) + * 3.1 [SRS](#srs) + * 3.2 [Normal Date Range](#normal-date-range) + * 3.3 [Extended Date Range](#extended-date-range) +* 4 [Requirements](#requirements) + * 4.1 [Generic](#generic) + * 4.1.0.1 [RQ.SRS-010.DateTime64.ExtendedRange](#rqsrs-010datetime64extendedrange) + * 4.1.0.2 [RQ.SRS-010.DateTime64.ExtendedRange.NormalRange.Start](#rqsrs-010datetime64extendedrangenormalrangestart) + * 4.1.0.3 [RQ.SRS-010.DateTime64.ExtendedRange.NormalRange.Start.BeforeEpochForTimeZone](#rqsrs-010datetime64extendedrangenormalrangestartbeforeepochfortimezone) + * 4.1.0.4 [RQ.SRS-010.DateTime64.ExtendedRange.NormalRange.End](#rqsrs-010datetime64extendedrangenormalrangeend) + * 4.1.0.5 [RQ.SRS-010.DateTime64.ExtendedRange.NormalRange.End.AfterEpochForTimeZone](#rqsrs-010datetime64extendedrangenormalrangeendafterepochfortimezone) + * 4.1.0.6 [RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions](#rqsrs-010datetime64extendedrangetypeconversionfunctions) + * 4.1.0.7 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions](#rqsrs-010datetime64extendedrangedatesandtimesfunctions) + * 4.1.0.8 [RQ.SRS-010.DateTime64.ExtendedRange.TimeZones](#rqsrs-010datetime64extendedrangetimezones) + * 4.1.0.9 [RQ.SRS-010.DateTime64.ExtendedRange.NonExistentTime](#rqsrs-010datetime64extendedrangenonexistenttime) + * 4.1.0.10 [RQ.SRS-010.DateTime64.ExtendedRange.Comparison](#rqsrs-010datetime64extendedrangecomparison) + * 4.1.0.11 [RQ.SRS-010.DateTime64.ExtendedRange.SpecificTimestamps](#rqsrs-010datetime64extendedrangespecifictimestamps) + * 4.2 [Specific](#specific) + * 4.2.0.1 [RQ.SRS-010.DateTime64.ExtendedRange.Start](#rqsrs-010datetime64extendedrangestart) + * 4.2.0.2 [RQ.SRS-010.DateTime64.ExtendedRange.Start.BeforeEpochForTimeZone](#rqsrs-010datetime64extendedrangestartbeforeepochfortimezone) + * 4.2.0.3 [RQ.SRS-010.DateTime64.ExtendedRange.End](#rqsrs-010datetime64extendedrangeend) + * 4.2.0.4 [RQ.SRS-010.DateTime64.ExtendedRange.End.AfterEpochForTimeZone](#rqsrs-010datetime64extendedrangeendafterepochfortimezone) + * 4.2.0.5 [Non-Existent Time](#non-existent-time) + * 4.2.0.5.1 [RQ.SRS-010.DateTime64.ExtendedRange.NonExistentTime.InvalidDate](#rqsrs-010datetime64extendedrangenonexistenttimeinvaliddate) + * 4.2.0.5.2 [RQ.SRS-010.DateTime64.ExtendedRange.NonExistentTime.InvalidTime](#rqsrs-010datetime64extendedrangenonexistenttimeinvalidtime) + * 4.2.0.5.3 [RQ.SRS-010.DateTime64.ExtendedRange.NonExistentTime.TimeZoneSwitch](#rqsrs-010datetime64extendedrangenonexistenttimetimezoneswitch) + * 4.2.0.5.4 [RQ.SRS-010.DateTime64.ExtendedRange.NonExistentTime.DaylightSavingTime](#rqsrs-010datetime64extendedrangenonexistenttimedaylightsavingtime) + * 4.2.0.5.5 [RQ.SRS-010.DateTime64.ExtendedRange.NonExistentTime.DaylightSavingTime.Disappeared](#rqsrs-010datetime64extendedrangenonexistenttimedaylightsavingtimedisappeared) + * 4.2.0.5.6 [RQ.SRS-010.DateTime64.ExtendedRange.NonExistentTime.LeapSeconds](#rqsrs-010datetime64extendedrangenonexistenttimeleapseconds) + * 4.2.0.6 [Dates And Times Functions](#dates-and-times-functions) + * 4.2.0.6.1 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toTimeZone](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstotimezone) + * 4.2.0.6.2 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toYear](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstoyear) + * 4.2.0.6.3 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toQuarter](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstoquarter) + * 4.2.0.6.4 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toMonth](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstomonth) + * 4.2.0.6.5 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toDayOfYear](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstodayofyear) + * 4.2.0.6.6 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toDayOfMonth](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstodayofmonth) + * 4.2.0.6.7 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toDayOfWeek](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstodayofweek) + * 4.2.0.6.8 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toHour](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstohour) + * 4.2.0.6.9 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toMinute](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstominute) + * 4.2.0.6.10 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toSecond](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstosecond) + * 4.2.0.6.11 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toUnixTimestamp](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstounixtimestamp) + * 4.2.0.6.12 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toStartOfYear](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstostartofyear) + * 4.2.0.6.13 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toStartOfISOYear](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstostartofisoyear) + * 4.2.0.6.14 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toStartOfQuarter](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstostartofquarter) + * 4.2.0.6.15 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toStartOfMonth](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstostartofmonth) + * 4.2.0.6.16 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toMonday](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstomonday) + * 4.2.0.6.17 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toStartOfWeek](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstostartofweek) + * 4.2.0.6.18 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toStartOfDay](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstostartofday) + * 4.2.0.6.19 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toStartOfHour](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstostartofhour) + * 4.2.0.6.20 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toStartOfMinute](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstostartofminute) + * 4.2.0.6.21 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toStartOfSecond](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstostartofsecond) + * 4.2.0.6.22 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toStartOfFiveMinute](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstostartoffiveminute) + * 4.2.0.6.23 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toStartOfTenMinutes](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstostartoftenminutes) + * 4.2.0.6.24 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toStartOfFifteenMinutes](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstostartoffifteenminutes) + * 4.2.0.6.25 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toStartOfInterval](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstostartofinterval) + * 4.2.0.6.26 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toTime](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstotime) + * 4.2.0.6.27 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toRelativeYearNum](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstorelativeyearnum) + * 4.2.0.6.28 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toRelativeQuarterNum](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstorelativequarternum) + * 4.2.0.6.29 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toRelativeMonthNum](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstorelativemonthnum) + * 4.2.0.6.30 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toRelativeWeekNum](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstorelativeweeknum) + * 4.2.0.6.31 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toRelativeDayNum](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstorelativedaynum) + * 4.2.0.6.32 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toRelativeHourNum](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstorelativehournum) + * 4.2.0.6.33 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toRelativeMinuteNum](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstorelativeminutenum) + * 4.2.0.6.34 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toRelativeSecondNum](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstorelativesecondnum) + * 4.2.0.6.35 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toISOYear](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstoisoyear) + * 4.2.0.6.36 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toISOWeek](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstoisoweek) + * 4.2.0.6.37 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toWeek](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstoweek) + * 4.2.0.6.38 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toYearWeek](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstoyearweek) + * 4.2.0.6.39 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.now](#rqsrs-010datetime64extendedrangedatesandtimesfunctionsnow) + * 4.2.0.6.40 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.today](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstoday) + * 4.2.0.6.41 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.yesterday](#rqsrs-010datetime64extendedrangedatesandtimesfunctionsyesterday) + * 4.2.0.6.42 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.timeSlot](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstimeslot) + * 4.2.0.6.43 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toYYYYMM](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstoyyyymm) + * 4.2.0.6.44 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toYYYYMMDD](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstoyyyymmdd) + * 4.2.0.6.45 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toYYYYMMDDhhmmss](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstoyyyymmddhhmmss) + * 4.2.0.6.46 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.addYears](#rqsrs-010datetime64extendedrangedatesandtimesfunctionsaddyears) + * 4.2.0.6.47 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.addMonths](#rqsrs-010datetime64extendedrangedatesandtimesfunctionsaddmonths) + * 4.2.0.6.48 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.addWeeks](#rqsrs-010datetime64extendedrangedatesandtimesfunctionsaddweeks) + * 4.2.0.6.49 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.addDays](#rqsrs-010datetime64extendedrangedatesandtimesfunctionsadddays) + * 4.2.0.6.50 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.addHours](#rqsrs-010datetime64extendedrangedatesandtimesfunctionsaddhours) + * 4.2.0.6.51 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.addMinutes](#rqsrs-010datetime64extendedrangedatesandtimesfunctionsaddminutes) + * 4.2.0.6.52 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.addSeconds](#rqsrs-010datetime64extendedrangedatesandtimesfunctionsaddseconds) + * 4.2.0.6.53 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.addQuarters](#rqsrs-010datetime64extendedrangedatesandtimesfunctionsaddquarters) + * 4.2.0.6.54 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.subtractYears](#rqsrs-010datetime64extendedrangedatesandtimesfunctionssubtractyears) + * 4.2.0.6.55 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.subtractMonths](#rqsrs-010datetime64extendedrangedatesandtimesfunctionssubtractmonths) + * 4.2.0.6.56 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.subtractWeeks](#rqsrs-010datetime64extendedrangedatesandtimesfunctionssubtractweeks) + * 4.2.0.6.57 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.subtractDays](#rqsrs-010datetime64extendedrangedatesandtimesfunctionssubtractdays) + * 4.2.0.6.58 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.subtractHours](#rqsrs-010datetime64extendedrangedatesandtimesfunctionssubtracthours) + * 4.2.0.6.59 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.subtractMinutes](#rqsrs-010datetime64extendedrangedatesandtimesfunctionssubtractminutes) + * 4.2.0.6.60 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.subtractSeconds](#rqsrs-010datetime64extendedrangedatesandtimesfunctionssubtractseconds) + * 4.2.0.6.61 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.subtractQuarters](#rqsrs-010datetime64extendedrangedatesandtimesfunctionssubtractquarters) + * 4.2.0.6.62 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.dateDiff](#rqsrs-010datetime64extendedrangedatesandtimesfunctionsdatediff) + * 4.2.0.6.63 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.timeSlots](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstimeslots) + * 4.2.0.6.64 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.formatDateTime](#rqsrs-010datetime64extendedrangedatesandtimesfunctionsformatdatetime) + * 4.2.1 [Type Conversion Functions](#type-conversion-functions) + * 4.2.1.6.1 [RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions.toInt(8|16|32|64|128|256)](#rqsrs-010datetime64extendedrangetypeconversionfunctionstoint8163264128256) + * 4.2.1.6.2 [RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions.toUInt(8|16|32|64|256)](#rqsrs-010datetime64extendedrangetypeconversionfunctionstouint8163264256) + * 4.2.1.6.3 [RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions.toFloat(32|64)](#rqsrs-010datetime64extendedrangetypeconversionfunctionstofloat3264) + * 4.2.1.6.4 [RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions.toDate](#rqsrs-010datetime64extendedrangetypeconversionfunctionstodate) + * 4.2.1.6.5 [RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions.toDateTime](#rqsrs-010datetime64extendedrangetypeconversionfunctionstodatetime) + * 4.2.1.6.6 [RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions.toDateTime64](#rqsrs-010datetime64extendedrangetypeconversionfunctionstodatetime64) + * 4.2.1.6.7 [RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions.toDateTime64.FromString.MissingTime](#rqsrs-010datetime64extendedrangetypeconversionfunctionstodatetime64fromstringmissingtime) + * 4.2.1.6.8 [RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions.toDecimal(32|64|128|256)](#rqsrs-010datetime64extendedrangetypeconversionfunctionstodecimal3264128256) + * 4.2.1.6.9 [RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions.toString](#rqsrs-010datetime64extendedrangetypeconversionfunctionstostring) + * 4.2.1.6.10 [RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions.CAST(x,T)](#rqsrs-010datetime64extendedrangetypeconversionfunctionscastxt) + * 4.2.1.6.11 [RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions.toUnixTimestamp64Milli](#rqsrs-010datetime64extendedrangetypeconversionfunctionstounixtimestamp64milli) + * 4.2.1.6.12 [RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions.toUnixTimestamp64Micro](#rqsrs-010datetime64extendedrangetypeconversionfunctionstounixtimestamp64micro) + * 4.2.1.6.13 [RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions.toUnixTimestamp64Nano](#rqsrs-010datetime64extendedrangetypeconversionfunctionstounixtimestamp64nano) + * 4.2.1.6.14 [RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions.fromUnixTimestamp64Milli](#rqsrs-010datetime64extendedrangetypeconversionfunctionsfromunixtimestamp64milli) + * 4.2.1.6.15 [RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions.fromUnixTimestamp64Micro](#rqsrs-010datetime64extendedrangetypeconversionfunctionsfromunixtimestamp64micro) + * 4.2.1.6.16 [RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions.fromUnixTimestamp64Nano](#rqsrs-010datetime64extendedrangetypeconversionfunctionsfromunixtimestamp64nano) +* 5 [References](#references) + +## Revision History + +This document is stored in an electronic form using [Git] source control management software +hosted in a [GitHub Repository]. +All the updates are tracked using the [Revision History]. + +## Introduction + +This document will cover requirements to support extended range for the [DateTime64] data type +that is outside the normal **1970** (1970-01-02 00:00:00 UTC) to **2105** (2105-12-31 23:59:59.99999 UTC) date range. + +## Terminology + +### SRS + +Software Requirements Specification + +### Normal Date Range + +**1970** `1970-01-02T00:00:00.000000` to **2105** `2105-12-31T23:59:59.99999` + +### Extended Date Range + +**1698** `1698-01-01T00:00:00.000000` to **2377** `2377-12-31 23:59:59.99999` + +## Requirements + +### Generic + +##### RQ.SRS-010.DateTime64.ExtendedRange +version: 1.0 + +[ClickHouse] SHALL support extended range for the [DateTime64] data type that includes dates from the year **1925** to **2377**. + +##### RQ.SRS-010.DateTime64.ExtendedRange.NormalRange.Start +version: 1.0 + +[ClickHouse] SHALL support proper time handling around the normal date range that starts at `1970-01-01 00:00:00.000` +expressed using the [ISO 8601 format]. + +##### RQ.SRS-010.DateTime64.ExtendedRange.NormalRange.Start.BeforeEpochForTimeZone +version: 1.0 + +[ClickHouse] SHALL support proper time handling around the start of the [normal date range] +when this time for the time zone is before the start of the [normal date range]. + +##### RQ.SRS-010.DateTime64.ExtendedRange.NormalRange.End +version: 1.0 + +[ClickHouse] SHALL support proper time handling around the normal date range that ends at `2105-12-31T23:59:59.99999` +expressed using the [ISO 8601 format]. + +##### RQ.SRS-010.DateTime64.ExtendedRange.NormalRange.End.AfterEpochForTimeZone +version: 1.0 + +[ClickHouse] SHALL support proper time handling around the end of the [normal date range] +when this time for the time zone is after the end of the [normal date range]. + +##### RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions +version: 1.0 + +[ClickHouse] SHALL support proper conversion to and from [DateTime64] data type from other data types. + +##### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [Dates and Times Functions] with the [DateTime64] data type +when it stores dates within the [normal date range] and the [extended date range]. + +##### RQ.SRS-010.DateTime64.ExtendedRange.TimeZones +version: 1.0 + +[ClickHouse] SHALL support correct operation with the [DateTime64] extended range data type +when combined with a supported time zone. + +##### RQ.SRS-010.DateTime64.ExtendedRange.NonExistentTime +version: 1.0 + +[ClickHouse] SHALL support proper handling of non-existent times when using [DateTime64] extended range data type. + +##### RQ.SRS-010.DateTime64.ExtendedRange.Comparison +version: 1.0 + +[ClickHouse] SHALL support proper handling of time comparison when using [DateTime64] extended range data type. +For example, `SELECT toDateTime64('2019-05-05 20:20:12.050', 3) < now()`. + +##### RQ.SRS-010.DateTime64.ExtendedRange.SpecificTimestamps +version: 1.0 + +[ClickHouse] SHALL properly work with the following timestamps in all supported timezones: +``` +[9961200,73476000,325666800,354675600,370400400,386125200,388566010,401850000,417574811,496803600,528253200,624423614,636516015,671011200,717555600,752047218,859683600,922582800,1018173600,1035705600,1143334800,1162105223,1174784400,1194156000,1206838823,1224982823,1236495624,1319936400,1319936424,1425798025,1459040400,1509872400,2090451627,2140668000] +``` + + +### Specific + +##### RQ.SRS-010.DateTime64.ExtendedRange.Start +version: 1.0 + +[ClickHouse] SHALL support extended range for the [DateTime64] data type that starts at `1698-01-01T00:00:00.000000` +expressed using the [ISO 8601 format]. + +##### RQ.SRS-010.DateTime64.ExtendedRange.Start.BeforeEpochForTimeZone +version: 1.0 + +[ClickHouse] SHALL support proper time handling around the start of the [extended date range] +when this time for the time zone is before the start of the [extended date range]. + +##### RQ.SRS-010.DateTime64.ExtendedRange.End +version: 1.0 + +[ClickHouse] SHALL support extended range for the [DateTime64] data type that ends at `2377-12-31T23:59:59.999999` +expressed using the [ISO 8601 format]. + +##### RQ.SRS-010.DateTime64.ExtendedRange.End.AfterEpochForTimeZone +version: 1.0 + +[ClickHouse] SHALL support proper time handling around the end of the [extended date range] +when this time for the time zone is after the end of the [extended date range]. + +##### Non-Existent Time + +###### RQ.SRS-010.DateTime64.ExtendedRange.NonExistentTime.InvalidDate +version: 1.0 + +[ClickHouse] SHALL support proper handling of invalid dates when using [DateTime64] extended range data type, +such as: + +* `YYYY-04-31, YYYY-06-31, YYYY-09-31, YYYY-11-31` +* `1990-02-30 00:00:02` + +###### RQ.SRS-010.DateTime64.ExtendedRange.NonExistentTime.InvalidTime +version: 1.0 + +[ClickHouse] SHALL support proper handling of invalid time for a timezone +when using [DateTime64] extended range data type, for example, + +* `2002-04-07 02:30:00` never happened at all in the US/Eastern timezone ([Stuart Bishop: pytz library](http://pytz.sourceforge.net/#problems-with-localtime)) + + +###### RQ.SRS-010.DateTime64.ExtendedRange.NonExistentTime.TimeZoneSwitch +version: 1.0 + +[ClickHouse] SHALL support proper handling of invalid time when using [DateTime64] extended range data type +when the invalid time is caused when *countries switch timezone definitions with no +daylight savings time switch* [Stuart Bishop: pytz library](http://pytz.sourceforge.net/#problems-with-localtime). + +> +> For example, in 1915 Warsaw switched from Warsaw time to Central European time with +> no daylight savings transition. So at the stroke of midnight on August 5th 1915 the clocks +> were wound back 24 minutes creating an ambiguous time period that cannot be specified without +> referring to the timezone abbreviation or the actual UTC offset. In this case midnight happened twice, +> neither time during a daylight saving time period. pytz handles this transition by treating the ambiguous +> period before the switch as daylight savings time, and the ambiguous period after as standard time. +> +> [Stuart Bishop: pytz library](http://pytz.sourceforge.net/#problems-with-localtime) + +###### RQ.SRS-010.DateTime64.ExtendedRange.NonExistentTime.DaylightSavingTime +version: 1.0 + +[ClickHouse] SHALL support proper handling of invalid time when using [DateTime64] extended range data type +when for a given timezone time switches from standard to daylight saving. + +> For example, in the US/Eastern timezone on the last Sunday morning in October, the following sequence happens: +> +> 01:00 EDT occurs +> 1 hour later, instead of 2:00am the clock is turned back 1 hour and 01:00 happens again (this time 01:00 EST) +> In fact, every instant between 01:00 and 02:00 occurs twice. +> [Stuart Bishop: pytz library](http://pytz.sourceforge.net/#problems-with-localtime) + +###### RQ.SRS-010.DateTime64.ExtendedRange.NonExistentTime.DaylightSavingTime.Disappeared +version: 1.0 + +[ClickHouse] SHALL support proper handling of invalid time when using [DateTime64] extended range data type +for a given timezone when transition from the standard to daylight saving time causes an hour to disappear. + +Expected behavior: if DateTime64 initialized by a skipped time value, it is being treated as DST and resulting value will be an hour earlier, e.g. `SELECT toDateTime64('2020-03-08 02:34:00', 0, 'America/Denver')` returns `2020-03-08 01:34:00`. + +###### RQ.SRS-010.DateTime64.ExtendedRange.NonExistentTime.LeapSeconds +version: 1.0 + +[ClickHouse] SHALL support proper handling of leap seconds adjustments when using [DateTime64] extended range data type. + +##### Dates And Times Functions + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toTimeZone +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [toTimeZone](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#totimezone) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toYear +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [toYear](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#toyear) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toQuarter +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [toQuarter](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#toquarter) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toMonth +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [toMonth](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#tomonth) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toDayOfYear +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [toDayOfYear](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#todayofyear) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toDayOfMonth +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [toDayOfMonth](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#todayofmonth) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toDayOfWeek +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [toDayOfWeek](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#todayofweek) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toHour +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [toHour](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#tohour) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toMinute +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [toMinute](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#tominute) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toSecond +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [toSecond](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#tosecond) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toUnixTimestamp +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [toUnitTimestamp](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#to-unix-timestamp) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. +Timestamp value expected to be negative when DateTime64 value is prior to `1970-01-01` and positine otherwise. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toStartOfYear +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [toStartOfYear](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#tostartofyear) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toStartOfISOYear +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [toStartOfISOYear](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#tostartofisoyear) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toStartOfQuarter +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [toStartOfQuarter](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#tostartofquarter) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toStartOfMonth +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [toStartOfMonth](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#tostartofmonth) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toMonday +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [toMonday](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#tomonday) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toStartOfWeek +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [toStartOfWeek](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#tostartofweektmode) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toStartOfDay +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [toStartOfDay](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#tostartofday) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toStartOfHour +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [toStartOfHour](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#tostartofhour) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toStartOfMinute +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [toStartOfMinute](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#tostartofminute) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toStartOfSecond +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [toStartOfSecond](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#tostartofsecond) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toStartOfFiveMinute +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [toStartOfFiveMinute](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#tostartoffiveminute) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toStartOfTenMinutes +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [toStartOfTenMinutes](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#tostartoftenminutes) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toStartOfFifteenMinutes +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [toStartOfFifteenMinutes](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#tostartoffifteenminutes) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toStartOfInterval +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [toStartOfInterval](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#tostartofintervaltime-or-data-interval-x-unit-time-zone) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. +More detailed description can be found [here](https://github.com/ClickHouse/ClickHouse/issues/1201). + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toTime +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [toTime](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#totime) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toRelativeYearNum +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [toRelativeYearNum](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#torelativeyearnum) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toRelativeQuarterNum +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [toRelativeQuarterNum](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#torelativequarternum) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toRelativeMonthNum +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [toRelativeMonthNum](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#torelativemonthnum) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toRelativeWeekNum +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [toRelativeWeekNum](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#torelativeweeknum) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toRelativeDayNum +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [toRelativeDayNum](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#torelativedaynum) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toRelativeHourNum +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [toRelativeHourNum](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#torelativehournum) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toRelativeMinuteNum +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [toRelativeMinuteNum](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#torelativeminutenum) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toRelativeSecondNum +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [toRelativeSecondNum](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#torelativesecondnum) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toISOYear +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [toISOYear](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#toisoyear) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toISOWeek +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [toISOWeek](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#toisoweek) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toWeek +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [toWeek](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#toweekdatemode) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toYearWeek +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [toYearWeek](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#toyearweekdatemode) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.now +version: 1.0 + +[ClickHouse] SHALL support conversion of output from the [now](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#now) +function to the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.today +version: 1.0 + +[ClickHouse] SHALL support conversion of output from the [today](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#today) +function to the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.yesterday +version: 1.0 + +[ClickHouse] SHALL support conversion of output from the [yesterday](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#yesterday) +function to the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.timeSlot +version: 1.0 + +[ClickHouse] SHALL support conversion of output from the [timeSlot](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#timeslot) +function to the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toYYYYMM +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [toYYYYMM](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#toyyyymm) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toYYYYMMDD +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [toYYYYMMDD](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#toyyyymmdd) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toYYYYMMDDhhmmss +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [toYYYYMMDDhhmmss](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#toyyyymmddhhmmss) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.addYears +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [addYears](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#addyears-addmonths-addweeks-adddays-addhours-addminutes-addseconds-addquarters) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.addMonths +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [addMonths](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#addyears-addmonths-addweeks-adddays-addhours-addminutes-addseconds-addquarters) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.addWeeks +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [addWeeks](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#addyears-addmonths-addweeks-adddays-addhours-addminutes-addseconds-addquarters) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.addDays +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [addDays](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#addyears-addmonths-addweeks-adddays-addhours-addminutes-addseconds-addquarters) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.addHours +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [addHours](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#addyears-addmonths-addweeks-adddays-addhours-addminutes-addseconds-addquarters) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.addMinutes +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [addMinutes](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#addyears-addmonths-addweeks-adddays-addhours-addminutes-addseconds-addquarters) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.addSeconds +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [addSeconds](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#addyears-addmonths-addweeks-adddays-addhours-addminutes-addseconds-addquarters) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.addQuarters +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [addQuarters](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#addyears-addmonths-addweeks-adddays-addhours-addminutes-addseconds-addquarters) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.subtractYears +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [subtractYears](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#subtractyears-subtractmonths-subtractweeks-subtractdays-subtracthours-subtractminutes-subtractseconds-subtractquarters) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.subtractMonths +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [subtractMonths](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#subtractyears-subtractmonths-subtractweeks-subtractdays-subtracthours-subtractminutes-subtractseconds-subtractquarters) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.subtractWeeks +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [subtractWeeks](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#subtractyears-subtractmonths-subtractweeks-subtractdays-subtracthours-subtractminutes-subtractseconds-subtractquarters) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.subtractDays +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [subtractDays](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#subtractyears-subtractmonths-subtractweeks-subtractdays-subtracthours-subtractminutes-subtractseconds-subtractquarters) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.subtractHours +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [subtractHours](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#subtractyears-subtractmonths-subtractweeks-subtractdays-subtracthours-subtractminutes-subtractseconds-subtractquarters) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.subtractMinutes +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [subtractMinutes](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#subtractyears-subtractmonths-subtractweeks-subtractdays-subtracthours-subtractminutes-subtractseconds-subtractquarters) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.subtractSeconds +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [subtractSeconds](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#subtractyears-subtractmonths-subtractweeks-subtractdays-subtracthours-subtractminutes-subtractseconds-subtractquarters) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.subtractQuarters +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [subtractQuarters](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#subtractyears-subtractmonths-subtractweeks-subtractdays-subtracthours-subtractminutes-subtractseconds-subtractquarters) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.dateDiff +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [dateDiff](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#datediff) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.timeSlots +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [timeSlots](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#timeslotsstarttime-duration-size) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.formatDateTime +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [formatDateTime](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#formatdatetime) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + + +#### Type Conversion Functions + +###### RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions.toInt(8|16|32|64|128|256) +version: 1.0 + +[ClickHouse] SHALL support correct conversion of the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range] +to integer types using [toInt(8|16|32|64|128|256)](https://clickhouse.tech/docs/en/sql-reference/functions/type-conversion-functions/#toint8163264128256) functions. + +###### RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions.toUInt(8|16|32|64|256) +version: 1.0 + +[ClickHouse] SHALL support correct conversion of the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range] +to unsigned integer types using [toUInt(8|16|32|64|256)](https://clickhouse.tech/docs/en/sql-reference/functions/type-conversion-functions/#touint8163264256) functions. + +###### RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions.toFloat(32|64) +version: 1.0 + +[ClickHouse] SHALL support correct conversion of the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range] +to float types using [toFloat(32|64)](https://clickhouse.tech/docs/en/sql-reference/functions/type-conversion-functions/#tofloat3264) functions. + +###### RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions.toDate +version: 1.0 + +[ClickHouse] SHALL support correct conversion of the [DateTime64] data type when it stores dates within the [normal date range] +to the [Date](https://clickhouse.tech/docs/en/sql-reference/data-types/date/) type using the [toDate](https://clickhouse.tech/docs/en/sql-reference/functions/type-conversion-functions/#todate) function. +This function is ONLY supposed to work in NORMAL RANGE. + +###### RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions.toDateTime +version: 1.0 + +[ClickHouse] SHALL support correct conversion of the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range] +to the [DateTime](https://clickhouse.tech/docs/en/sql-reference/data-types/datetime/) type using the [toDateTime](https://clickhouse.tech/docs/en/sql-reference/functions/type-conversion-functions/#todatetime) function. +This function is ONLY supposed to work in NORMAL RANGE. + +###### RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions.toDateTime64 +version: 1.0 + +[ClickHouse] SHALL support correct conversion from the data types supported by the [toDateTime64](https://clickhouse.tech/docs/en/sql-reference/data-types/datetime64/) function +to the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions.toDateTime64.FromString.MissingTime +version: 1.0 + +[ClickHouse] SHALL support correct conversion from the [String](https://clickhouse.tech/docs/en/sql-reference/data-types/string/) +data type to the [DateTime64](https://clickhouse.tech/docs/en/sql-reference/data-types/datetime64/) data type +when value of the string is missing the `hh:mm-ss.sss` part. +For example, `toDateTime64('2020-01-01', 3)`. + +###### RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions.toDecimal(32|64|128|256) +version: 1.0 + +[ClickHouse] SHALL support correct conversion of the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range] +to [Decimal](https://clickhouse.tech/docs/en/sql-reference/data-types/decimal/) types using [toDecimal(32|64|128|256)](https://clickhouse.tech/docs/en/sql-reference/functions/type-conversion-functions/#todecimal3264128256) functions. + +###### RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions.toString +version: 1.0 + +[ClickHouse] SHALL support correct conversion of the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range] +to the [String](https://clickhouse.tech/docs/en/sql-reference/data-types/string/) type using the [toString](https://clickhouse.tech/docs/en/sql-reference/functions/type-conversion-functions/#tostring) function. + +###### RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions.CAST(x,T) +version: 1.0 + +[ClickHouse] SHALL support correct conversion of the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range] +to one of the supported data type using the [CAST(x,T)](https://clickhouse.tech/docs/en/sql-reference/functions/type-conversion-functions/#type_conversion_function-cast) function. + +###### RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions.toUnixTimestamp64Milli +version: 1.0 + +[ClickHouse] SHALL support correct conversion of the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range] +to the [Int64](https://clickhouse.tech/docs/en/sql-reference/data-types/int-uint/) type using the [toUnixTimestamp64Milli](https://clickhouse.tech/docs/en/sql-reference/functions/type-conversion-functions/#tounixtimestamp64milli) function. + +###### RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions.toUnixTimestamp64Micro +version: 1.0 + +[ClickHouse] SHALL support correct conversion of the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range] +to the [Int64](https://clickhouse.tech/docs/en/sql-reference/data-types/int-uint/) type using the [toUnixTimestamp64Micro](https://clickhouse.tech/docs/en/sql-reference/functions/type-conversion-functions/#tounixtimestamp64micro) function. + +###### RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions.toUnixTimestamp64Nano +version: 1.0 + +[ClickHouse] SHALL support correct conversion of the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range] +to the [Int64](https://clickhouse.tech/docs/en/sql-reference/data-types/int-uint/) type using the [toUnixTimestamp64Nano](https://clickhouse.tech/docs/en/sql-reference/functions/type-conversion-functions/#tounixtimestamp64nano) function. + +###### RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions.fromUnixTimestamp64Milli +version: 1.0 + +[ClickHouse] SHALL support correct conversion from the [Int64](https://clickhouse.tech/docs/en/sql-reference/data-types/int-uint/) type +to the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range] +using the [fromUnixTimestamp64Milli](https://clickhouse.tech/docs/en/sql-reference/functions/type-conversion-functions/#fromunixtimestamp64milli) function. + +###### RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions.fromUnixTimestamp64Micro +version: 1.0 + +[ClickHouse] SHALL support correct conversion from the [Int64](https://clickhouse.tech/docs/en/sql-reference/data-types/int-uint/) type +to the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range] +using the [fromUnixTimestamp64Micro](https://clickhouse.tech/docs/en/sql-reference/functions/type-conversion-functions/#fromunixtimestamp64micro) function. + +###### RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions.fromUnixTimestamp64Nano +version: 1.0 + +[ClickHouse] SHALL support correct conversion from the [Int64](https://clickhouse.tech/docs/en/sql-reference/data-types/int-uint/) type +to the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range] +using the [fromUnixTimestamp64Nano](https://clickhouse.tech/docs/en/sql-reference/functions/type-conversion-functions/#fromunixtimestamp64nano) function. + +## References + +* **DateTime64**: https://clickhouse.tech/docs/en/sql-reference/data-types/datetime64/ +* **ISO 8601 format**: https://en.wikipedia.org/wiki/ISO_8601 +* **ClickHouse:** https://clickhouse.tech +* **GitHub Repository:** https://github.com/ClickHouse/ClickHouse/blob/master/tests/testflows/datetime64_extended_range/requirements/requirements.md +* **Revision History:** https://github.com/ClickHouse/ClickHouse/commits/master/tests/testflows/datetime64_extended_range/requirements/requirements.md +* **Git:** https://git-scm.com/ + +[SRS]: #srs +[normal date range]: #normal-date-range +[extended date range]: #extended-date-range +[Dates and Times Functions]: https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/ +[DateTime64]: https://clickhouse.tech/docs/en/sql-reference/data-types/datetime64/ +[ISO 8601 format]: https://en.wikipedia.org/wiki/ISO_8601 +[ClickHouse]: https://clickhouse.tech +[GitHub Repository]: https://github.com/ClickHouse/ClickHouse/blob/master/tests/testflows/datetime64_extended_range/requirements/requirements.md +[Revision History]: https://github.com/ClickHouse/ClickHouse/commits/master/tests/testflows/datetime64_extended_range/requirements/requirements.md +[Git]: https://git-scm.com/ +[GitHub]: https://github.com diff --git a/tests/testflows/datetime64_extended_range/requirements/requirements.py b/tests/testflows/datetime64_extended_range/requirements/requirements.py new file mode 100644 index 00000000000..ea2934eaa13 --- /dev/null +++ b/tests/testflows/datetime64_extended_range/requirements/requirements.py @@ -0,0 +1,2313 @@ +# These requirements were auto generated +# from software requirements specification (SRS) +# document by TestFlows v1.6.201102.1235648. +# Do not edit by hand but re-generate instead +# using 'tfs requirements generate' command. +from testflows.core import Specification +from testflows.core import Requirement + +QA_SRS010_ClickHouse_DateTime64_Extended_Range = Specification( + name='QA-SRS010 ClickHouse DateTime64 Extended Range', + description=None, + author='vzakaznikov, zvonand', + date='August 10, 2020', + status='-', + approved_by='-', + approved_date='-', + approved_version='-', + version=None, + group=None, + type=None, + link=None, + uid=None, + parent=None, + children=None, + content=''' +# QA-SRS010 ClickHouse DateTime64 Extended Range +# Software Requirements Specification + +(c) 2020 Altinity LTD. All Rights Reserved. + +**Document status:** Confidential + +**Author:** vzakaznikov, zvonand + +**Date:** August 10, 2020 + +## Approval + +**Status:** - + +**Version:** - + +**Approved by:** - + +**Date:** - + +## Table of Contents + +* 1 [Revision History](#revision-history) +* 2 [Introduction](#introduction) +* 3 [Terminology](#terminology) + * 3.1 [SRS](#srs) + * 3.2 [Normal Date Range](#normal-date-range) + * 3.3 [Extended Date Range](#extended-date-range) +* 4 [Requirements](#requirements) + * 4.1 [Generic](#generic) + * 4.1.0.1 [RQ.SRS-010.DateTime64.ExtendedRange](#rqsrs-010datetime64extendedrange) + * 4.1.0.2 [RQ.SRS-010.DateTime64.ExtendedRange.NormalRange.Start](#rqsrs-010datetime64extendedrangenormalrangestart) + * 4.1.0.3 [RQ.SRS-010.DateTime64.ExtendedRange.NormalRange.Start.BeforeEpochForTimeZone](#rqsrs-010datetime64extendedrangenormalrangestartbeforeepochfortimezone) + * 4.1.0.4 [RQ.SRS-010.DateTime64.ExtendedRange.NormalRange.End](#rqsrs-010datetime64extendedrangenormalrangeend) + * 4.1.0.5 [RQ.SRS-010.DateTime64.ExtendedRange.NormalRange.End.AfterEpochForTimeZone](#rqsrs-010datetime64extendedrangenormalrangeendafterepochfortimezone) + * 4.1.0.6 [RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions](#rqsrs-010datetime64extendedrangetypeconversionfunctions) + * 4.1.0.7 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions](#rqsrs-010datetime64extendedrangedatesandtimesfunctions) + * 4.1.0.8 [RQ.SRS-010.DateTime64.ExtendedRange.TimeZones](#rqsrs-010datetime64extendedrangetimezones) + * 4.1.0.9 [RQ.SRS-010.DateTime64.ExtendedRange.NonExistentTime](#rqsrs-010datetime64extendedrangenonexistenttime) + * 4.1.0.10 [RQ.SRS-010.DateTime64.ExtendedRange.Comparison](#rqsrs-010datetime64extendedrangecomparison) + * 4.1.0.11 [RQ.SRS-010.DateTime64.ExtendedRange.SpecificTimestamps](#rqsrs-010datetime64extendedrangespecifictimestamps) + * 4.2 [Specific](#specific) + * 4.2.0.1 [RQ.SRS-010.DateTime64.ExtendedRange.Start](#rqsrs-010datetime64extendedrangestart) + * 4.2.0.2 [RQ.SRS-010.DateTime64.ExtendedRange.Start.BeforeEpochForTimeZone](#rqsrs-010datetime64extendedrangestartbeforeepochfortimezone) + * 4.2.0.3 [RQ.SRS-010.DateTime64.ExtendedRange.End](#rqsrs-010datetime64extendedrangeend) + * 4.2.0.4 [RQ.SRS-010.DateTime64.ExtendedRange.End.AfterEpochForTimeZone](#rqsrs-010datetime64extendedrangeendafterepochfortimezone) + * 4.2.0.5 [Non-Existent Time](#non-existent-time) + * 4.2.0.5.1 [RQ.SRS-010.DateTime64.ExtendedRange.NonExistentTime.InvalidDate](#rqsrs-010datetime64extendedrangenonexistenttimeinvaliddate) + * 4.2.0.5.2 [RQ.SRS-010.DateTime64.ExtendedRange.NonExistentTime.InvalidTime](#rqsrs-010datetime64extendedrangenonexistenttimeinvalidtime) + * 4.2.0.5.3 [RQ.SRS-010.DateTime64.ExtendedRange.NonExistentTime.TimeZoneSwitch](#rqsrs-010datetime64extendedrangenonexistenttimetimezoneswitch) + * 4.2.0.5.4 [RQ.SRS-010.DateTime64.ExtendedRange.NonExistentTime.DaylightSavingTime](#rqsrs-010datetime64extendedrangenonexistenttimedaylightsavingtime) + * 4.2.0.5.5 [RQ.SRS-010.DateTime64.ExtendedRange.NonExistentTime.DaylightSavingTime.Disappeared](#rqsrs-010datetime64extendedrangenonexistenttimedaylightsavingtimedisappeared) + * 4.2.0.5.6 [RQ.SRS-010.DateTime64.ExtendedRange.NonExistentTime.LeapSeconds](#rqsrs-010datetime64extendedrangenonexistenttimeleapseconds) + * 4.2.0.6 [Dates And Times Functions](#dates-and-times-functions) + * 4.2.0.6.1 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toTimeZone](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstotimezone) + * 4.2.0.6.2 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toYear](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstoyear) + * 4.2.0.6.3 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toQuarter](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstoquarter) + * 4.2.0.6.4 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toMonth](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstomonth) + * 4.2.0.6.5 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toDayOfYear](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstodayofyear) + * 4.2.0.6.6 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toDayOfMonth](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstodayofmonth) + * 4.2.0.6.7 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toDayOfWeek](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstodayofweek) + * 4.2.0.6.8 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toHour](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstohour) + * 4.2.0.6.9 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toMinute](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstominute) + * 4.2.0.6.10 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toSecond](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstosecond) + * 4.2.0.6.11 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toUnixTimestamp](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstounixtimestamp) + * 4.2.0.6.12 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toStartOfYear](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstostartofyear) + * 4.2.0.6.13 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toStartOfISOYear](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstostartofisoyear) + * 4.2.0.6.14 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toStartOfQuarter](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstostartofquarter) + * 4.2.0.6.15 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toStartOfMonth](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstostartofmonth) + * 4.2.0.6.16 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toMonday](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstomonday) + * 4.2.0.6.17 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toStartOfWeek](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstostartofweek) + * 4.2.0.6.18 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toStartOfDay](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstostartofday) + * 4.2.0.6.19 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toStartOfHour](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstostartofhour) + * 4.2.0.6.20 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toStartOfMinute](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstostartofminute) + * 4.2.0.6.21 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toStartOfSecond](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstostartofsecond) + * 4.2.0.6.22 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toStartOfFiveMinute](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstostartoffiveminute) + * 4.2.0.6.23 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toStartOfTenMinutes](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstostartoftenminutes) + * 4.2.0.6.24 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toStartOfFifteenMinutes](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstostartoffifteenminutes) + * 4.2.0.6.25 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toStartOfInterval](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstostartofinterval) + * 4.2.0.6.26 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toTime](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstotime) + * 4.2.0.6.27 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toRelativeYearNum](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstorelativeyearnum) + * 4.2.0.6.28 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toRelativeQuarterNum](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstorelativequarternum) + * 4.2.0.6.29 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toRelativeMonthNum](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstorelativemonthnum) + * 4.2.0.6.30 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toRelativeWeekNum](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstorelativeweeknum) + * 4.2.0.6.31 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toRelativeDayNum](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstorelativedaynum) + * 4.2.0.6.32 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toRelativeHourNum](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstorelativehournum) + * 4.2.0.6.33 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toRelativeMinuteNum](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstorelativeminutenum) + * 4.2.0.6.34 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toRelativeSecondNum](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstorelativesecondnum) + * 4.2.0.6.35 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toISOYear](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstoisoyear) + * 4.2.0.6.36 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toISOWeek](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstoisoweek) + * 4.2.0.6.37 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toWeek](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstoweek) + * 4.2.0.6.38 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toYearWeek](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstoyearweek) + * 4.2.0.6.39 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.now](#rqsrs-010datetime64extendedrangedatesandtimesfunctionsnow) + * 4.2.0.6.40 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.today](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstoday) + * 4.2.0.6.41 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.yesterday](#rqsrs-010datetime64extendedrangedatesandtimesfunctionsyesterday) + * 4.2.0.6.42 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.timeSlot](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstimeslot) + * 4.2.0.6.43 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toYYYYMM](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstoyyyymm) + * 4.2.0.6.44 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toYYYYMMDD](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstoyyyymmdd) + * 4.2.0.6.45 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toYYYYMMDDhhmmss](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstoyyyymmddhhmmss) + * 4.2.0.6.46 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.addYears](#rqsrs-010datetime64extendedrangedatesandtimesfunctionsaddyears) + * 4.2.0.6.47 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.addMonths](#rqsrs-010datetime64extendedrangedatesandtimesfunctionsaddmonths) + * 4.2.0.6.48 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.addWeeks](#rqsrs-010datetime64extendedrangedatesandtimesfunctionsaddweeks) + * 4.2.0.6.49 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.addDays](#rqsrs-010datetime64extendedrangedatesandtimesfunctionsadddays) + * 4.2.0.6.50 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.addHours](#rqsrs-010datetime64extendedrangedatesandtimesfunctionsaddhours) + * 4.2.0.6.51 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.addMinutes](#rqsrs-010datetime64extendedrangedatesandtimesfunctionsaddminutes) + * 4.2.0.6.52 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.addSeconds](#rqsrs-010datetime64extendedrangedatesandtimesfunctionsaddseconds) + * 4.2.0.6.53 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.addQuarters](#rqsrs-010datetime64extendedrangedatesandtimesfunctionsaddquarters) + * 4.2.0.6.54 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.subtractYears](#rqsrs-010datetime64extendedrangedatesandtimesfunctionssubtractyears) + * 4.2.0.6.55 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.subtractMonths](#rqsrs-010datetime64extendedrangedatesandtimesfunctionssubtractmonths) + * 4.2.0.6.56 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.subtractWeeks](#rqsrs-010datetime64extendedrangedatesandtimesfunctionssubtractweeks) + * 4.2.0.6.57 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.subtractDays](#rqsrs-010datetime64extendedrangedatesandtimesfunctionssubtractdays) + * 4.2.0.6.58 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.subtractHours](#rqsrs-010datetime64extendedrangedatesandtimesfunctionssubtracthours) + * 4.2.0.6.59 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.subtractMinutes](#rqsrs-010datetime64extendedrangedatesandtimesfunctionssubtractminutes) + * 4.2.0.6.60 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.subtractSeconds](#rqsrs-010datetime64extendedrangedatesandtimesfunctionssubtractseconds) + * 4.2.0.6.61 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.subtractQuarters](#rqsrs-010datetime64extendedrangedatesandtimesfunctionssubtractquarters) + * 4.2.0.6.62 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.dateDiff](#rqsrs-010datetime64extendedrangedatesandtimesfunctionsdatediff) + * 4.2.0.6.63 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.timeSlots](#rqsrs-010datetime64extendedrangedatesandtimesfunctionstimeslots) + * 4.2.0.6.64 [RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.formatDateTime](#rqsrs-010datetime64extendedrangedatesandtimesfunctionsformatdatetime) + * 4.2.1 [Type Conversion Functions](#type-conversion-functions) + * 4.2.1.6.1 [RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions.toInt(8|16|32|64|128|256)](#rqsrs-010datetime64extendedrangetypeconversionfunctionstoint8163264128256) + * 4.2.1.6.2 [RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions.toUInt(8|16|32|64|256)](#rqsrs-010datetime64extendedrangetypeconversionfunctionstouint8163264256) + * 4.2.1.6.3 [RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions.toFloat(32|64)](#rqsrs-010datetime64extendedrangetypeconversionfunctionstofloat3264) + * 4.2.1.6.4 [RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions.toDate](#rqsrs-010datetime64extendedrangetypeconversionfunctionstodate) + * 4.2.1.6.5 [RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions.toDateTime](#rqsrs-010datetime64extendedrangetypeconversionfunctionstodatetime) + * 4.2.1.6.6 [RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions.toDateTime64](#rqsrs-010datetime64extendedrangetypeconversionfunctionstodatetime64) + * 4.2.1.6.7 [RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions.toDateTime64.FromString.MissingTime](#rqsrs-010datetime64extendedrangetypeconversionfunctionstodatetime64fromstringmissingtime) + * 4.2.1.6.8 [RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions.toDecimal(32|64|128|256)](#rqsrs-010datetime64extendedrangetypeconversionfunctionstodecimal3264128256) + * 4.2.1.6.9 [RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions.toString](#rqsrs-010datetime64extendedrangetypeconversionfunctionstostring) + * 4.2.1.6.10 [RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions.CAST(x,T)](#rqsrs-010datetime64extendedrangetypeconversionfunctionscastxt) + * 4.2.1.6.11 [RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions.toUnixTimestamp64Milli](#rqsrs-010datetime64extendedrangetypeconversionfunctionstounixtimestamp64milli) + * 4.2.1.6.12 [RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions.toUnixTimestamp64Micro](#rqsrs-010datetime64extendedrangetypeconversionfunctionstounixtimestamp64micro) + * 4.2.1.6.13 [RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions.toUnixTimestamp64Nano](#rqsrs-010datetime64extendedrangetypeconversionfunctionstounixtimestamp64nano) + * 4.2.1.6.14 [RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions.fromUnixTimestamp64Milli](#rqsrs-010datetime64extendedrangetypeconversionfunctionsfromunixtimestamp64milli) + * 4.2.1.6.15 [RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions.fromUnixTimestamp64Micro](#rqsrs-010datetime64extendedrangetypeconversionfunctionsfromunixtimestamp64micro) + * 4.2.1.6.16 [RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions.fromUnixTimestamp64Nano](#rqsrs-010datetime64extendedrangetypeconversionfunctionsfromunixtimestamp64nano) +* 5 [References](#references) + +## Revision History + +This document is stored in an electronic form using [Git] source control management software +hosted in a [GitLab Repository]. +All the updates are tracked using the [Revision History]. + +## Introduction + +This document will cover requirements to support extended range for the [DateTime64] data type +that is outside the normal **1970** (1970-01-02 00:00:00 UTC) to **2105** (2105-12-31 23:59:59.99999 UTC) date range. + +## Terminology + +### SRS + +Software Requirements Specification + +### Normal Date Range + +**1970** `1970-01-02T00:00:00.000000` to **2105** `2105-12-31T23:59:59.99999` + +### Extended Date Range + +**1698** `1698-01-01T00:00:00.000000` to **2377** `2377-12-31 23:59:59.99999` + +## Requirements + +### Generic + +##### RQ.SRS-010.DateTime64.ExtendedRange +version: 1.0 + +[ClickHouse] SHALL support extended range for the [DateTime64] data type that includes dates from the year **1698** to **2377**. + +##### RQ.SRS-010.DateTime64.ExtendedRange.NormalRange.Start +version: 1.0 + +[ClickHouse] SHALL support proper time handling around the normal date range that starts at `1970-01-01 00:00:00.000` +expressed using the [ISO 8601 format]. + +##### RQ.SRS-010.DateTime64.ExtendedRange.NormalRange.Start.BeforeEpochForTimeZone +version: 1.0 + +[ClickHouse] SHALL support proper time handling around the start of the [normal date range] +when this time for the time zone is before the start of the [normal date range]. + +##### RQ.SRS-010.DateTime64.ExtendedRange.NormalRange.End +version: 1.0 + +[ClickHouse] SHALL support proper time handling around the normal date range that ends at `2105-12-31T23:59:59.99999` +expressed using the [ISO 8601 format]. + +##### RQ.SRS-010.DateTime64.ExtendedRange.NormalRange.End.AfterEpochForTimeZone +version: 1.0 + +[ClickHouse] SHALL support proper time handling around the end of the [normal date range] +when this time for the time zone is after the end of the [normal date range]. + +##### RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions +version: 1.0 + +[ClickHouse] SHALL support proper conversion to and from [DateTime64] data type from other data types. + +##### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [Dates and Times Functions] with the [DateTime64] data type +when it stores dates within the [normal date range] and the [extended date range]. + +##### RQ.SRS-010.DateTime64.ExtendedRange.TimeZones +version: 1.0 + +[ClickHouse] SHALL support correct operation with the [DateTime64] extended range data type +when combined with a supported time zone. + +##### RQ.SRS-010.DateTime64.ExtendedRange.NonExistentTime +version: 1.0 + +[ClickHouse] SHALL support proper handling of non-existent times when using [DateTime64] extended range data type. + +##### RQ.SRS-010.DateTime64.ExtendedRange.Comparison +version: 1.0 + +[ClickHouse] SHALL support proper handling of time comparison when using [DateTime64] extended range data type. +For example, `SELECT toDateTime64('2019-05-05 20:20:12.050', 3) < now()`. + +##### RQ.SRS-010.DateTime64.ExtendedRange.SpecificTimestamps +version: 1.0 + +[ClickHouse] SHALL properly work with the following timestamps in all supported timezones: +``` +[9961200,73476000,325666800,354675600,370400400,386125200,388566010,401850000,417574811,496803600,528253200,624423614,636516015,671011200,717555600,752047218,859683600,922582800,1018173600,1035705600,1143334800,1162105223,1174784400,1194156000,1206838823,1224982823,1236495624,1319936400,1319936424,1425798025,1459040400,1509872400,2090451627,2140668000] +``` + + +### Specific + +##### RQ.SRS-010.DateTime64.ExtendedRange.Start +version: 1.0 + +[ClickHouse] SHALL support extended range for the [DateTime64] data type that starts at `1698-01-01T00:00:00.000000` +expressed using the [ISO 8601 format]. + +##### RQ.SRS-010.DateTime64.ExtendedRange.Start.BeforeEpochForTimeZone +version: 1.0 + +[ClickHouse] SHALL support proper time handling around the start of the [extended date range] +when this time for the time zone is before the start of the [extended date range]. + +##### RQ.SRS-010.DateTime64.ExtendedRange.End +version: 1.0 + +[ClickHouse] SHALL support extended range for the [DateTime64] data type that ends at `2377-12-31T23:59:59.999999` +expressed using the [ISO 8601 format]. + +##### RQ.SRS-010.DateTime64.ExtendedRange.End.AfterEpochForTimeZone +version: 1.0 + +[ClickHouse] SHALL support proper time handling around the end of the [extended date range] +when this time for the time zone is after the end of the [extended date range]. + +##### Non-Existent Time + +###### RQ.SRS-010.DateTime64.ExtendedRange.NonExistentTime.InvalidDate +version: 1.0 + +[ClickHouse] SHALL support proper handling of invalid dates when using [DateTime64] extended range data type, +such as: + +* `YYYY-04-31, YYYY-06-31, YYYY-09-31, YYYY-11-31` +* `1990-02-30 00:00:02` + +###### RQ.SRS-010.DateTime64.ExtendedRange.NonExistentTime.InvalidTime +version: 1.0 + +[ClickHouse] SHALL support proper handling of invalid time for a timezone +when using [DateTime64] extended range data type, for example, + +* `2002-04-07 02:30:00` never happened at all in the US/Eastern timezone ([Stuart Bishop: pytz library](http://pytz.sourceforge.net/#problems-with-localtime)) + + +###### RQ.SRS-010.DateTime64.ExtendedRange.NonExistentTime.TimeZoneSwitch +version: 1.0 + +[ClickHouse] SHALL support proper handling of invalid time when using [DateTime64] extended range data type +when the invalid time is caused when *countries switch timezone definitions with no +daylight savings time switch* [Stuart Bishop: pytz library](http://pytz.sourceforge.net/#problems-with-localtime). + +> +> For example, in 1915 Warsaw switched from Warsaw time to Central European time with +> no daylight savings transition. So at the stroke of midnight on August 5th 1915 the clocks +> were wound back 24 minutes creating an ambiguous time period that cannot be specified without +> referring to the timezone abbreviation or the actual UTC offset. In this case midnight happened twice, +> neither time during a daylight saving time period. pytz handles this transition by treating the ambiguous +> period before the switch as daylight savings time, and the ambiguous period after as standard time. +> +> [Stuart Bishop: pytz library](http://pytz.sourceforge.net/#problems-with-localtime) + +###### RQ.SRS-010.DateTime64.ExtendedRange.NonExistentTime.DaylightSavingTime +version: 1.0 + +[ClickHouse] SHALL support proper handling of invalid time when using [DateTime64] extended range data type +when for a given timezone time switches from standard to daylight saving. + +> For example, in the US/Eastern timezone on the last Sunday morning in October, the following sequence happens: +> +> 01:00 EDT occurs +> 1 hour later, instead of 2:00am the clock is turned back 1 hour and 01:00 happens again (this time 01:00 EST) +> In fact, every instant between 01:00 and 02:00 occurs twice. +> [Stuart Bishop: pytz library](http://pytz.sourceforge.net/#problems-with-localtime) + +###### RQ.SRS-010.DateTime64.ExtendedRange.NonExistentTime.DaylightSavingTime.Disappeared +version: 1.0 + +[ClickHouse] SHALL support proper handling of invalid time when using [DateTime64] extended range data type +for a given timezone when transition from the standard to daylight saving time causes an hour to disappear. + +Expected behavior: if DateTime64 initialized by a skipped time value, it is being treated as DST and resulting value will be an hour earlier, e.g. `SELECT toDateTime64('2020-03-08 02:34:00', 0, 'America/Denver')` returns `2020-03-08 01:34:00`. + +###### RQ.SRS-010.DateTime64.ExtendedRange.NonExistentTime.LeapSeconds +version: 1.0 + +[ClickHouse] SHALL support proper handling of leap seconds adjustments when using [DateTime64] extended range data type. + +##### Dates And Times Functions + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toTimeZone +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [toTimeZone](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#totimezone) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toYear +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [toYear](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#toyear) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toQuarter +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [toQuarter](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#toquarter) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toMonth +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [toMonth](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#tomonth) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toDayOfYear +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [toDayOfYear](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#todayofyear) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toDayOfMonth +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [toDayOfMonth](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#todayofmonth) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toDayOfWeek +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [toDayOfWeek](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#todayofweek) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toHour +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [toHour](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#tohour) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toMinute +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [toMinute](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#tominute) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toSecond +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [toSecond](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#tosecond) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toUnixTimestamp +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [toUnitTimestamp](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#to-unix-timestamp) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. +Timestamp value expected to be negative when DateTime64 value is prior to `1970-01-01` and positine otherwise. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toStartOfYear +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [toStartOfYear](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#tostartofyear) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toStartOfISOYear +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [toStartOfISOYear](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#tostartofisoyear) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toStartOfQuarter +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [toStartOfQuarter](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#tostartofquarter) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toStartOfMonth +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [toStartOfMonth](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#tostartofmonth) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toMonday +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [toMonday](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#tomonday) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toStartOfWeek +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [toStartOfWeek](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#tostartofweektmode) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toStartOfDay +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [toStartOfDay](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#tostartofday) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toStartOfHour +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [toStartOfHour](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#tostartofhour) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toStartOfMinute +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [toStartOfMinute](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#tostartofminute) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toStartOfSecond +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [toStartOfSecond](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#tostartofsecond) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toStartOfFiveMinute +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [toStartOfFiveMinute](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#tostartoffiveminute) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toStartOfTenMinutes +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [toStartOfTenMinutes](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#tostartoftenminutes) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toStartOfFifteenMinutes +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [toStartOfFifteenMinutes](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#tostartoffifteenminutes) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toStartOfInterval +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [toStartOfInterval](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#tostartofintervaltime-or-data-interval-x-unit-time-zone) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. +More detailed description can be found [here](https://github.com/ClickHouse/ClickHouse/issues/1201). + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toTime +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [toTime](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#totime) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toRelativeYearNum +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [toRelativeYearNum](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#torelativeyearnum) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toRelativeQuarterNum +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [toRelativeQuarterNum](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#torelativequarternum) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toRelativeMonthNum +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [toRelativeMonthNum](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#torelativemonthnum) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toRelativeWeekNum +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [toRelativeWeekNum](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#torelativeweeknum) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toRelativeDayNum +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [toRelativeDayNum](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#torelativedaynum) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toRelativeHourNum +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [toRelativeHourNum](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#torelativehournum) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toRelativeMinuteNum +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [toRelativeMinuteNum](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#torelativeminutenum) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toRelativeSecondNum +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [toRelativeSecondNum](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#torelativesecondnum) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toISOYear +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [toISOYear](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#toisoyear) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toISOWeek +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [toISOWeek](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#toisoweek) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toWeek +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [toWeek](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#toweekdatemode) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toYearWeek +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [toYearWeek](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#toyearweekdatemode) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.now +version: 1.0 + +[ClickHouse] SHALL support conversion of output from the [now](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#now) +function to the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.today +version: 1.0 + +[ClickHouse] SHALL support conversion of output from the [today](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#today) +function to the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.yesterday +version: 1.0 + +[ClickHouse] SHALL support conversion of output from the [yesterday](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#yesterday) +function to the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.timeSlot +version: 1.0 + +[ClickHouse] SHALL support conversion of output from the [timeSlot](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#timeslot) +function to the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toYYYYMM +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [toYYYYMM](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#toyyyymm) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toYYYYMMDD +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [toYYYYMMDD](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#toyyyymmdd) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toYYYYMMDDhhmmss +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [toYYYYMMDDhhmmss](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#toyyyymmddhhmmss) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.addYears +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [addYears](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#addyears-addmonths-addweeks-adddays-addhours-addminutes-addseconds-addquarters) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.addMonths +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [addMonths](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#addyears-addmonths-addweeks-adddays-addhours-addminutes-addseconds-addquarters) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.addWeeks +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [addWeeks](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#addyears-addmonths-addweeks-adddays-addhours-addminutes-addseconds-addquarters) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.addDays +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [addDays](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#addyears-addmonths-addweeks-adddays-addhours-addminutes-addseconds-addquarters) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.addHours +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [addHours](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#addyears-addmonths-addweeks-adddays-addhours-addminutes-addseconds-addquarters) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.addMinutes +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [addMinutes](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#addyears-addmonths-addweeks-adddays-addhours-addminutes-addseconds-addquarters) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.addSeconds +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [addSeconds](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#addyears-addmonths-addweeks-adddays-addhours-addminutes-addseconds-addquarters) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.addQuarters +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [addQuarters](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#addyears-addmonths-addweeks-adddays-addhours-addminutes-addseconds-addquarters) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.subtractYears +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [subtractYears](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#subtractyears-subtractmonths-subtractweeks-subtractdays-subtracthours-subtractminutes-subtractseconds-subtractquarters) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.subtractMonths +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [subtractMonths](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#subtractyears-subtractmonths-subtractweeks-subtractdays-subtracthours-subtractminutes-subtractseconds-subtractquarters) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.subtractWeeks +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [subtractWeeks](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#subtractyears-subtractmonths-subtractweeks-subtractdays-subtracthours-subtractminutes-subtractseconds-subtractquarters) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.subtractDays +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [subtractDays](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#subtractyears-subtractmonths-subtractweeks-subtractdays-subtracthours-subtractminutes-subtractseconds-subtractquarters) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.subtractHours +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [subtractHours](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#subtractyears-subtractmonths-subtractweeks-subtractdays-subtracthours-subtractminutes-subtractseconds-subtractquarters) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.subtractMinutes +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [subtractMinutes](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#subtractyears-subtractmonths-subtractweeks-subtractdays-subtracthours-subtractminutes-subtractseconds-subtractquarters) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.subtractSeconds +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [subtractSeconds](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#subtractyears-subtractmonths-subtractweeks-subtractdays-subtracthours-subtractminutes-subtractseconds-subtractquarters) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.subtractQuarters +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [subtractQuarters](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#subtractyears-subtractmonths-subtractweeks-subtractdays-subtracthours-subtractminutes-subtractseconds-subtractquarters) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.dateDiff +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [dateDiff](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#datediff) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.timeSlots +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [timeSlots](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#timeslotsstarttime-duration-size) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.formatDateTime +version: 1.0 + +[ClickHouse] SHALL support correct operation of the [formatDateTime](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#formatdatetime) +function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + + +#### Type Conversion Functions + +###### RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions.toInt(8|16|32|64|128|256) +version: 1.0 + +[ClickHouse] SHALL support correct conversion of the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range] +to integer types using [toInt(8|16|32|64|128|256)](https://clickhouse.tech/docs/en/sql-reference/functions/type-conversion-functions/#toint8163264128256) functions. + +###### RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions.toUInt(8|16|32|64|256) +version: 1.0 + +[ClickHouse] SHALL support correct conversion of the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range] +to unsigned integer types using [toUInt(8|16|32|64|256)](https://clickhouse.tech/docs/en/sql-reference/functions/type-conversion-functions/#touint8163264256) functions. + +###### RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions.toFloat(32|64) +version: 1.0 + +[ClickHouse] SHALL support correct conversion of the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range] +to float types using [toFloat(32|64)](https://clickhouse.tech/docs/en/sql-reference/functions/type-conversion-functions/#tofloat3264) functions. + +###### RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions.toDate +version: 1.0 + +[ClickHouse] SHALL support correct conversion of the [DateTime64] data type when it stores dates within the [normal date range] +to the [Date](https://clickhouse.tech/docs/en/sql-reference/data-types/date/) type using the [toDate](https://clickhouse.tech/docs/en/sql-reference/functions/type-conversion-functions/#todate) function. +This function is ONLY supposed to work in NORMAL RANGE. + +###### RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions.toDateTime +version: 1.0 + +[ClickHouse] SHALL support correct conversion of the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range] +to the [DateTime](https://clickhouse.tech/docs/en/sql-reference/data-types/datetime/) type using the [toDateTime](https://clickhouse.tech/docs/en/sql-reference/functions/type-conversion-functions/#todatetime) function. +This function is ONLY supposed to work in NORMAL RANGE. + +###### RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions.toDateTime64 +version: 1.0 + +[ClickHouse] SHALL support correct conversion from the data types supported by the [toDateTime64](https://clickhouse.tech/docs/en/sql-reference/data-types/datetime64/) function +to the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]. + +###### RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions.toDateTime64.FromString.MissingTime +version: 1.0 + +[ClickHouse] SHALL support correct conversion from the [String](https://clickhouse.tech/docs/en/sql-reference/data-types/string/) +data type to the [DateTime64](https://clickhouse.tech/docs/en/sql-reference/data-types/datetime64/) data type +when value of the string is missing the `hh:mm-ss.sss` part. +For example, `toDateTime64('2020-01-01', 3)`. + +###### RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions.toDecimal(32|64|128|256) +version: 1.0 + +[ClickHouse] SHALL support correct conversion of the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range] +to [Decimal](https://clickhouse.tech/docs/en/sql-reference/data-types/decimal/) types using [toDecimal(32|64|128|256)](https://clickhouse.tech/docs/en/sql-reference/functions/type-conversion-functions/#todecimal3264128256) functions. + +###### RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions.toString +version: 1.0 + +[ClickHouse] SHALL support correct conversion of the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range] +to the [String](https://clickhouse.tech/docs/en/sql-reference/data-types/string/) type using the [toString](https://clickhouse.tech/docs/en/sql-reference/functions/type-conversion-functions/#tostring) function. + +###### RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions.CAST(x,T) +version: 1.0 + +[ClickHouse] SHALL support correct conversion of the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range] +to one of the supported data type using the [CAST(x,T)](https://clickhouse.tech/docs/en/sql-reference/functions/type-conversion-functions/#type_conversion_function-cast) function. + +###### RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions.toUnixTimestamp64Milli +version: 1.0 + +[ClickHouse] SHALL support correct conversion of the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range] +to the [Int64](https://clickhouse.tech/docs/en/sql-reference/data-types/int-uint/) type using the [toUnixTimestamp64Milli](https://clickhouse.tech/docs/en/sql-reference/functions/type-conversion-functions/#tounixtimestamp64milli) function. + +###### RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions.toUnixTimestamp64Micro +version: 1.0 + +[ClickHouse] SHALL support correct conversion of the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range] +to the [Int64](https://clickhouse.tech/docs/en/sql-reference/data-types/int-uint/) type using the [toUnixTimestamp64Micro](https://clickhouse.tech/docs/en/sql-reference/functions/type-conversion-functions/#tounixtimestamp64micro) function. + +###### RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions.toUnixTimestamp64Nano +version: 1.0 + +[ClickHouse] SHALL support correct conversion of the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range] +to the [Int64](https://clickhouse.tech/docs/en/sql-reference/data-types/int-uint/) type using the [toUnixTimestamp64Nano](https://clickhouse.tech/docs/en/sql-reference/functions/type-conversion-functions/#tounixtimestamp64nano) function. + +###### RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions.fromUnixTimestamp64Milli +version: 1.0 + +[ClickHouse] SHALL support correct conversion from the [Int64](https://clickhouse.tech/docs/en/sql-reference/data-types/int-uint/) type +to the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range] +using the [fromUnixTimestamp64Milli](https://clickhouse.tech/docs/en/sql-reference/functions/type-conversion-functions/#fromunixtimestamp64milli) function. + +###### RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions.fromUnixTimestamp64Micro +version: 1.0 + +[ClickHouse] SHALL support correct conversion from the [Int64](https://clickhouse.tech/docs/en/sql-reference/data-types/int-uint/) type +to the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range] +using the [fromUnixTimestamp64Micro](https://clickhouse.tech/docs/en/sql-reference/functions/type-conversion-functions/#fromunixtimestamp64micro) function. + +###### RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions.fromUnixTimestamp64Nano +version: 1.0 + +[ClickHouse] SHALL support correct conversion from the [Int64](https://clickhouse.tech/docs/en/sql-reference/data-types/int-uint/) type +to the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range] +using the [fromUnixTimestamp64Nano](https://clickhouse.tech/docs/en/sql-reference/functions/type-conversion-functions/#fromunixtimestamp64nano) function. + +## References + +* **DateTime64**: https://clickhouse.tech/docs/en/sql-reference/data-types/datetime64/ +* **ISO 8601 format**: https://en.wikipedia.org/wiki/ISO_8601 +* **ClickHouse:** https://clickhouse.tech +* **GitLab Repository:** https://gitlab.com/altinity-qa/documents/qa-srs010-clickhouse-datetime64-extended-range/-/blob/master/QA_SRS010_ClickHouse_DateTime64_Extended_Range.md +* **Revision History:** https://gitlab.com/altinity-qa/documents/qa-srs010-clickhouse-datetime64-extended-range/-/commits/master/QA_SRS010_ClickHouse_DateTime64_Extended_Range.md +* **Git:** https://git-scm.com/ + +[SRS]: #srs +[normal date range]: #normal-date-range +[extended date range]: #extended-date-range +[Dates and Times Functions]: https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/ +[DateTime64]: https://clickhouse.tech/docs/en/sql-reference/data-types/datetime64/ +[ISO 8601 format]: https://en.wikipedia.org/wiki/ISO_8601 +[ClickHouse]: https://clickhouse.tech +[GitLab Repository]: https://gitlab.com/altinity-qa/documents/qa-srs010-clickhouse-datetime64-extended-range/-/blob/master/QA_SRS010_ClickHouse_DateTime64_Extended_Range.md +[Revision History]: https://gitlab.com/altinity-qa/documents/qa-srs010-clickhouse-datetime64-extended-range/-/commits/master/QA_SRS010_ClickHouse_DateTime64_Extended_Range.md +[Git]: https://git-scm.com/ +[GitLab]: https://gitlab.com +''') + +RQ_SRS_010_DateTime64_ExtendedRange = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support extended range for the [DateTime64] data type that includes dates from the year **1698** to **2377**.\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_NormalRange_Start = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.NormalRange.Start', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support proper time handling around the normal date range that starts at `1970-01-01 00:00:00.000`\n' + 'expressed using the [ISO 8601 format].\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_NormalRange_Start_BeforeEpochForTimeZone = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.NormalRange.Start.BeforeEpochForTimeZone', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support proper time handling around the start of the [normal date range]\n' + 'when this time for the time zone is before the start of the [normal date range].\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_NormalRange_End = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.NormalRange.End', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support proper time handling around the normal date range that ends at `2105-12-31T23:59:59.99999`\n' + 'expressed using the [ISO 8601 format].\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_NormalRange_End_AfterEpochForTimeZone = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.NormalRange.End.AfterEpochForTimeZone', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support proper time handling around the end of the [normal date range]\n' + 'when this time for the time zone is after the end of the [normal date range].\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_TypeConversionFunctions = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support proper conversion to and from [DateTime64] data type from other data types.\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support correct operation of the [Dates and Times Functions] with the [DateTime64] data type\n' + 'when it stores dates within the [normal date range] and the [extended date range].\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_TimeZones = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.TimeZones', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support correct operation with the [DateTime64] extended range data type\n' + 'when combined with a supported time zone.\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_NonExistentTime = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.NonExistentTime', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support proper handling of non-existent times when using [DateTime64] extended range data type.\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_Comparison = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.Comparison', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support proper handling of time comparison when using [DateTime64] extended range data type.\n' + "For example, `SELECT toDateTime64('2019-05-05 20:20:12.050', 3) < now()`.\n" + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_SpecificTimestamps = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.SpecificTimestamps', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL properly work with the following timestamps in all supported timezones:\n' + '```\n' + '[9961200,73476000,325666800,354675600,370400400,386125200,388566010,401850000,417574811,496803600,528253200,624423614,636516015,671011200,717555600,752047218,859683600,922582800,1018173600,1035705600,1143334800,1162105223,1174784400,1194156000,1206838823,1224982823,1236495624,1319936400,1319936424,1425798025,1459040400,1509872400,2090451627,2140668000]\n' + '```\n' + '\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_Start = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.Start', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support extended range for the [DateTime64] data type that starts at `1698-01-01T00:00:00.000000`\n' + 'expressed using the [ISO 8601 format].\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_Start_BeforeEpochForTimeZone = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.Start.BeforeEpochForTimeZone', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support proper time handling around the start of the [extended date range]\n' + 'when this time for the time zone is before the start of the [extended date range].\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_End = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.End', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support extended range for the [DateTime64] data type that ends at `2377-12-31T23:59:59.999999`\n' + 'expressed using the [ISO 8601 format].\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_End_AfterEpochForTimeZone = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.End.AfterEpochForTimeZone', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support proper time handling around the end of the [extended date range]\n' + 'when this time for the time zone is after the end of the [extended date range].\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_NonExistentTime_InvalidDate = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.NonExistentTime.InvalidDate', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support proper handling of invalid dates when using [DateTime64] extended range data type,\n' + 'such as:\n' + '\n' + '* `YYYY-04-31, YYYY-06-31, YYYY-09-31, YYYY-11-31`\n' + '* `1990-02-30 00:00:02`\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_NonExistentTime_InvalidTime = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.NonExistentTime.InvalidTime', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support proper handling of invalid time for a timezone\n' + 'when using [DateTime64] extended range data type, for example,\n' + '\n' + '* `2002-04-07 02:30:00` never happened at all in the US/Eastern timezone ([Stuart Bishop: pytz library](http://pytz.sourceforge.net/#problems-with-localtime))\n' + '\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_NonExistentTime_TimeZoneSwitch = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.NonExistentTime.TimeZoneSwitch', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support proper handling of invalid time when using [DateTime64] extended range data type\n' + 'when the invalid time is caused when *countries switch timezone definitions with no\n' + 'daylight savings time switch* [Stuart Bishop: pytz library](http://pytz.sourceforge.net/#problems-with-localtime).\n' + '\n' + '>\n' + '> For example, in 1915 Warsaw switched from Warsaw time to Central European time with\n' + '> no daylight savings transition. So at the stroke of midnight on August 5th 1915 the clocks\n' + '> were wound back 24 minutes creating an ambiguous time period that cannot be specified without\n' + '> referring to the timezone abbreviation or the actual UTC offset. In this case midnight happened twice,\n' + '> neither time during a daylight saving time period. pytz handles this transition by treating the ambiguous\n' + '> period before the switch as daylight savings time, and the ambiguous period after as standard time.\n' + '>\n' + '> [Stuart Bishop: pytz library](http://pytz.sourceforge.net/#problems-with-localtime)\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_NonExistentTime_DaylightSavingTime = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.NonExistentTime.DaylightSavingTime', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support proper handling of invalid time when using [DateTime64] extended range data type\n' + 'when for a given timezone time switches from standard to daylight saving.\n' + '\n' + '> For example, in the US/Eastern timezone on the last Sunday morning in October, the following sequence happens:\n' + '>\n' + '> 01:00 EDT occurs\n' + '> 1 hour later, instead of 2:00am the clock is turned back 1 hour and 01:00 happens again (this time 01:00 EST)\n' + '> In fact, every instant between 01:00 and 02:00 occurs twice.\n' + '> [Stuart Bishop: pytz library](http://pytz.sourceforge.net/#problems-with-localtime)\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_NonExistentTime_DaylightSavingTime_Disappeared = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.NonExistentTime.DaylightSavingTime.Disappeared', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support proper handling of invalid time when using [DateTime64] extended range data type\n' + 'for a given timezone when transition from the standard to daylight saving time causes an hour to disappear.\n' + '\n' + "Expected behavior: if DateTime64 initialized by a skipped time value, it is being treated as DST and resulting value will be an hour earlier, e.g. `SELECT toDateTime64('2020-03-08 02:34:00', 0, 'America/Denver')` returns `2020-03-08 01:34:00`.\n" + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_NonExistentTime_LeapSeconds = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.NonExistentTime.LeapSeconds', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support proper handling of leap seconds adjustments when using [DateTime64] extended range data type.\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_toTimeZone = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toTimeZone', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support correct operation of the [toTimeZone](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#totimezone)\n' + 'function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range].\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_toYear = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toYear', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support correct operation of the [toYear](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#toyear)\n' + 'function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range].\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_toQuarter = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toQuarter', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support correct operation of the [toQuarter](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#toquarter)\n' + 'function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range].\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_toMonth = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toMonth', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support correct operation of the [toMonth](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#tomonth)\n' + 'function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range].\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_toDayOfYear = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toDayOfYear', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support correct operation of the [toDayOfYear](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#todayofyear)\n' + 'function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range].\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_toDayOfMonth = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toDayOfMonth', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support correct operation of the [toDayOfMonth](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#todayofmonth)\n' + 'function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range].\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_toDayOfWeek = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toDayOfWeek', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support correct operation of the [toDayOfWeek](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#todayofweek)\n' + 'function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range].\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_toHour = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toHour', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support correct operation of the [toHour](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#tohour)\n' + 'function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range].\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_toMinute = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toMinute', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support correct operation of the [toMinute](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#tominute)\n' + 'function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range].\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_toSecond = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toSecond', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support correct operation of the [toSecond](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#tosecond)\n' + 'function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range].\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_toUnixTimestamp = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toUnixTimestamp', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support correct operation of the [toUnitTimestamp](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#to-unix-timestamp)\n' + 'function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range].\n' + 'Timestamp value expected to be negative when DateTime64 value is prior to `1970-01-01` and positine otherwise.\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_toStartOfYear = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toStartOfYear', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support correct operation of the [toStartOfYear](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#tostartofyear)\n' + 'function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range].\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_toStartOfISOYear = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toStartOfISOYear', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support correct operation of the [toStartOfISOYear](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#tostartofisoyear)\n' + 'function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range].\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_toStartOfQuarter = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toStartOfQuarter', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support correct operation of the [toStartOfQuarter](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#tostartofquarter)\n' + 'function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range].\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_toStartOfMonth = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toStartOfMonth', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support correct operation of the [toStartOfMonth](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#tostartofmonth)\n' + 'function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range].\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_toMonday = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toMonday', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support correct operation of the [toMonday](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#tomonday)\n' + 'function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range].\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_toStartOfWeek = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toStartOfWeek', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support correct operation of the [toStartOfWeek](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#tostartofweektmode)\n' + 'function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range].\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_toStartOfDay = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toStartOfDay', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support correct operation of the [toStartOfDay](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#tostartofday)\n' + 'function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range].\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_toStartOfHour = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toStartOfHour', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support correct operation of the [toStartOfHour](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#tostartofhour)\n' + 'function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range].\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_toStartOfMinute = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toStartOfMinute', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support correct operation of the [toStartOfMinute](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#tostartofminute)\n' + 'function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range].\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_toStartOfSecond = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toStartOfSecond', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support correct operation of the [toStartOfSecond](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#tostartofsecond)\n' + 'function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range].\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_toStartOfFiveMinute = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toStartOfFiveMinute', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support correct operation of the [toStartOfFiveMinute](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#tostartoffiveminute)\n' + 'function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range].\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_toStartOfTenMinutes = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toStartOfTenMinutes', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support correct operation of the [toStartOfTenMinutes](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#tostartoftenminutes)\n' + 'function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range].\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_toStartOfFifteenMinutes = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toStartOfFifteenMinutes', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support correct operation of the [toStartOfFifteenMinutes](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#tostartoffifteenminutes)\n' + 'function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range].\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_toStartOfInterval = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toStartOfInterval', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support correct operation of the [toStartOfInterval](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#tostartofintervaltime-or-data-interval-x-unit-time-zone)\n' + 'function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range].\n' + 'More detailed description can be found [here](https://github.com/ClickHouse/ClickHouse/issues/1201).\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_toTime = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toTime', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support correct operation of the [toTime](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#totime)\n' + 'function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range].\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_toRelativeYearNum = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toRelativeYearNum', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support correct operation of the [toRelativeYearNum](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#torelativeyearnum)\n' + 'function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range].\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_toRelativeQuarterNum = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toRelativeQuarterNum', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support correct operation of the [toRelativeQuarterNum](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#torelativequarternum)\n' + 'function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range].\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_toRelativeMonthNum = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toRelativeMonthNum', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support correct operation of the [toRelativeMonthNum](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#torelativemonthnum)\n' + 'function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range].\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_toRelativeWeekNum = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toRelativeWeekNum', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support correct operation of the [toRelativeWeekNum](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#torelativeweeknum)\n' + 'function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range].\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_toRelativeDayNum = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toRelativeDayNum', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support correct operation of the [toRelativeDayNum](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#torelativedaynum)\n' + 'function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range].\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_toRelativeHourNum = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toRelativeHourNum', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support correct operation of the [toRelativeHourNum](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#torelativehournum)\n' + 'function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range].\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_toRelativeMinuteNum = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toRelativeMinuteNum', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support correct operation of the [toRelativeMinuteNum](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#torelativeminutenum)\n' + 'function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range].\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_toRelativeSecondNum = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toRelativeSecondNum', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support correct operation of the [toRelativeSecondNum](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#torelativesecondnum)\n' + 'function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range].\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_toISOYear = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toISOYear', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support correct operation of the [toISOYear](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#toisoyear)\n' + 'function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range].\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_toISOWeek = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toISOWeek', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support correct operation of the [toISOWeek](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#toisoweek)\n' + 'function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range].\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_toWeek = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toWeek', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support correct operation of the [toWeek](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#toweekdatemode)\n' + 'function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range].\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_toYearWeek = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toYearWeek', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support correct operation of the [toYearWeek](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#toyearweekdatemode)\n' + 'function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range].\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_now = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.now', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support conversion of output from the [now](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#now)\n' + 'function to the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range].\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_today = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.today', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support conversion of output from the [today](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#today)\n' + 'function to the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range].\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_yesterday = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.yesterday', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support conversion of output from the [yesterday](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#yesterday)\n' + 'function to the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range].\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_timeSlot = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.timeSlot', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support conversion of output from the [timeSlot](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#timeslot)\n' + 'function to the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range].\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_toYYYYMM = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toYYYYMM', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support correct operation of the [toYYYYMM](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#toyyyymm)\n' + 'function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range].\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_toYYYYMMDD = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toYYYYMMDD', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support correct operation of the [toYYYYMMDD](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#toyyyymmdd)\n' + 'function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range].\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_toYYYYMMDDhhmmss = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.toYYYYMMDDhhmmss', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support correct operation of the [toYYYYMMDDhhmmss](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#toyyyymmddhhmmss)\n' + 'function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range].\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_addYears = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.addYears', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support correct operation of the [addYears](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#addyears-addmonths-addweeks-adddays-addhours-addminutes-addseconds-addquarters)\n' + 'function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range].\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_addMonths = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.addMonths', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support correct operation of the [addMonths](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#addyears-addmonths-addweeks-adddays-addhours-addminutes-addseconds-addquarters)\n' + 'function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range].\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_addWeeks = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.addWeeks', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support correct operation of the [addWeeks](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#addyears-addmonths-addweeks-adddays-addhours-addminutes-addseconds-addquarters)\n' + 'function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range].\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_addDays = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.addDays', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support correct operation of the [addDays](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#addyears-addmonths-addweeks-adddays-addhours-addminutes-addseconds-addquarters)\n' + 'function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range].\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_addHours = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.addHours', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support correct operation of the [addHours](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#addyears-addmonths-addweeks-adddays-addhours-addminutes-addseconds-addquarters)\n' + 'function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range].\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_addMinutes = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.addMinutes', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support correct operation of the [addMinutes](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#addyears-addmonths-addweeks-adddays-addhours-addminutes-addseconds-addquarters)\n' + 'function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range].\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_addSeconds = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.addSeconds', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support correct operation of the [addSeconds](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#addyears-addmonths-addweeks-adddays-addhours-addminutes-addseconds-addquarters)\n' + 'function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range].\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_addQuarters = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.addQuarters', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support correct operation of the [addQuarters](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#addyears-addmonths-addweeks-adddays-addhours-addminutes-addseconds-addquarters)\n' + 'function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range].\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_subtractYears = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.subtractYears', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support correct operation of the [subtractYears](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#subtractyears-subtractmonths-subtractweeks-subtractdays-subtracthours-subtractminutes-subtractseconds-subtractquarters)\n' + 'function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range].\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_subtractMonths = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.subtractMonths', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support correct operation of the [subtractMonths](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#subtractyears-subtractmonths-subtractweeks-subtractdays-subtracthours-subtractminutes-subtractseconds-subtractquarters)\n' + 'function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range].\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_subtractWeeks = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.subtractWeeks', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support correct operation of the [subtractWeeks](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#subtractyears-subtractmonths-subtractweeks-subtractdays-subtracthours-subtractminutes-subtractseconds-subtractquarters)\n' + 'function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range].\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_subtractDays = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.subtractDays', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support correct operation of the [subtractDays](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#subtractyears-subtractmonths-subtractweeks-subtractdays-subtracthours-subtractminutes-subtractseconds-subtractquarters)\n' + 'function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range].\n' + '\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_subtractHours = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.subtractHours', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support correct operation of the [subtractHours](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#subtractyears-subtractmonths-subtractweeks-subtractdays-subtracthours-subtractminutes-subtractseconds-subtractquarters)\n' + 'function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range].\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_subtractMinutes = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.subtractMinutes', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support correct operation of the [subtractMinutes](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#subtractyears-subtractmonths-subtractweeks-subtractdays-subtracthours-subtractminutes-subtractseconds-subtractquarters)\n' + 'function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range].\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_subtractSeconds = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.subtractSeconds', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support correct operation of the [subtractSeconds](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#subtractyears-subtractmonths-subtractweeks-subtractdays-subtracthours-subtractminutes-subtractseconds-subtractquarters)\n' + 'function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range].\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_subtractQuarters = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.subtractQuarters', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support correct operation of the [subtractQuarters](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#subtractyears-subtractmonths-subtractweeks-subtractdays-subtracthours-subtractminutes-subtractseconds-subtractquarters)\n' + 'function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range].\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_dateDiff = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.dateDiff', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support correct operation of the [dateDiff](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#datediff)\n' + 'function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range].\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_timeSlots = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.timeSlots', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support correct operation of the [timeSlots](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#timeslotsstarttime-duration-size)\n' + 'function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range].\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_formatDateTime = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.DatesAndTimesFunctions.formatDateTime', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support correct operation of the [formatDateTime](https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#formatdatetime)\n' + 'function used with the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range].\n' + '\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_TypeConversionFunctions_toInt_8_16_32_64_128_256_ = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions.toInt(8|16|32|64|128|256)', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support correct conversion of the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]\n' + 'to integer types using [toInt(8|16|32|64|128|256)](https://clickhouse.tech/docs/en/sql-reference/functions/type-conversion-functions/#toint8163264128256) functions.\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_TypeConversionFunctions_toUInt_8_16_32_64_256_ = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions.toUInt(8|16|32|64|256)', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support correct conversion of the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]\n' + 'to unsigned integer types using [toUInt(8|16|32|64|256)](https://clickhouse.tech/docs/en/sql-reference/functions/type-conversion-functions/#touint8163264256) functions.\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_TypeConversionFunctions_toFloat_32_64_ = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions.toFloat(32|64)', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support correct conversion of the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]\n' + 'to float types using [toFloat(32|64)](https://clickhouse.tech/docs/en/sql-reference/functions/type-conversion-functions/#tofloat3264) functions.\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_TypeConversionFunctions_toDate = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions.toDate', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support correct conversion of the [DateTime64] data type when it stores dates within the [normal date range]\n' + 'to the [Date](https://clickhouse.tech/docs/en/sql-reference/data-types/date/) type using the [toDate](https://clickhouse.tech/docs/en/sql-reference/functions/type-conversion-functions/#todate) function.\n' + 'This function is ONLY supposed to work in NORMAL RANGE.\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_TypeConversionFunctions_toDateTime = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions.toDateTime', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support correct conversion of the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]\n' + 'to the [DateTime](https://clickhouse.tech/docs/en/sql-reference/data-types/datetime/) type using the [toDateTime](https://clickhouse.tech/docs/en/sql-reference/functions/type-conversion-functions/#todatetime) function.\n' + 'This function is ONLY supposed to work in NORMAL RANGE.\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_TypeConversionFunctions_toDateTime64 = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions.toDateTime64', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support correct conversion from the data types supported by the [toDateTime64](https://clickhouse.tech/docs/en/sql-reference/data-types/datetime64/) function\n' + 'to the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range].\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_TypeConversionFunctions_toDateTime64_FromString_MissingTime = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions.toDateTime64.FromString.MissingTime', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support correct conversion from the [String](https://clickhouse.tech/docs/en/sql-reference/data-types/string/)\n' + 'data type to the [DateTime64](https://clickhouse.tech/docs/en/sql-reference/data-types/datetime64/) data type\n' + 'when value of the string is missing the `hh:mm-ss.sss` part.\n' + "For example, `toDateTime64('2020-01-01', 3)`.\n" + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_TypeConversionFunctions_toDecimal_32_64_128_256_ = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions.toDecimal(32|64|128|256)', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support correct conversion of the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]\n' + 'to [Decimal](https://clickhouse.tech/docs/en/sql-reference/data-types/decimal/) types using [toDecimal(32|64|128|256)](https://clickhouse.tech/docs/en/sql-reference/functions/type-conversion-functions/#todecimal3264128256) functions.\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_TypeConversionFunctions_toString = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions.toString', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support correct conversion of the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]\n' + 'to the [String](https://clickhouse.tech/docs/en/sql-reference/data-types/string/) type using the [toString](https://clickhouse.tech/docs/en/sql-reference/functions/type-conversion-functions/#tostring) function.\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_TypeConversionFunctions_CAST_x_T_ = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions.CAST(x,T)', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support correct conversion of the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]\n' + 'to one of the supported data type using the [CAST(x,T)](https://clickhouse.tech/docs/en/sql-reference/functions/type-conversion-functions/#type_conversion_function-cast) function.\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_TypeConversionFunctions_toUnixTimestamp64Milli = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions.toUnixTimestamp64Milli', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support correct conversion of the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]\n' + 'to the [Int64](https://clickhouse.tech/docs/en/sql-reference/data-types/int-uint/) type using the [toUnixTimestamp64Milli](https://clickhouse.tech/docs/en/sql-reference/functions/type-conversion-functions/#tounixtimestamp64milli) function.\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_TypeConversionFunctions_toUnixTimestamp64Micro = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions.toUnixTimestamp64Micro', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support correct conversion of the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]\n' + 'to the [Int64](https://clickhouse.tech/docs/en/sql-reference/data-types/int-uint/) type using the [toUnixTimestamp64Micro](https://clickhouse.tech/docs/en/sql-reference/functions/type-conversion-functions/#tounixtimestamp64micro) function.\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_TypeConversionFunctions_toUnixTimestamp64Nano = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions.toUnixTimestamp64Nano', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support correct conversion of the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]\n' + 'to the [Int64](https://clickhouse.tech/docs/en/sql-reference/data-types/int-uint/) type using the [toUnixTimestamp64Nano](https://clickhouse.tech/docs/en/sql-reference/functions/type-conversion-functions/#tounixtimestamp64nano) function.\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_TypeConversionFunctions_fromUnixTimestamp64Milli = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions.fromUnixTimestamp64Milli', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support correct conversion from the [Int64](https://clickhouse.tech/docs/en/sql-reference/data-types/int-uint/) type\n' + 'to the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]\n' + 'using the [fromUnixTimestamp64Milli](https://clickhouse.tech/docs/en/sql-reference/functions/type-conversion-functions/#fromunixtimestamp64milli) function.\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_TypeConversionFunctions_fromUnixTimestamp64Micro = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions.fromUnixTimestamp64Micro', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support correct conversion from the [Int64](https://clickhouse.tech/docs/en/sql-reference/data-types/int-uint/) type\n' + 'to the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]\n' + 'using the [fromUnixTimestamp64Micro](https://clickhouse.tech/docs/en/sql-reference/functions/type-conversion-functions/#fromunixtimestamp64micro) function.\n' + '\n' + ), + link=None) + +RQ_SRS_010_DateTime64_ExtendedRange_TypeConversionFunctions_fromUnixTimestamp64Nano = Requirement( + name='RQ.SRS-010.DateTime64.ExtendedRange.TypeConversionFunctions.fromUnixTimestamp64Nano', + version='1.0', + priority=None, + group=None, + type=None, + uid=None, + description=( + '[ClickHouse] SHALL support correct conversion from the [Int64](https://clickhouse.tech/docs/en/sql-reference/data-types/int-uint/) type\n' + 'to the [DateTime64] data type when it stores dates within the [normal date range] and the [extended date range]\n' + 'using the [fromUnixTimestamp64Nano](https://clickhouse.tech/docs/en/sql-reference/functions/type-conversion-functions/#fromunixtimestamp64nano) function.\n' + '\n' + ), + link=None) diff --git a/tests/testflows/datetime64_extended_range/test.log b/tests/testflows/datetime64_extended_range/test.log new file mode 100644 index 0000000000000000000000000000000000000000..ce52ce6037fed70b85c9c77cf9c9e1f8b81d434a GIT binary patch literal 56172 zcma&NLzFH`(=__DZQHhO+qP}n-fi2q&E42-+qUg{?l=F}ddD@Yh{&u+)HjE>rZxZo zda}|Y4h$dyLI(fNXIS6Xm+4Hr)*LkaxU_#a9D6&A{}OUkyWnG%j5M_$38fJ3!p#>k2G&;zS)X>A zP1$B~@G@wPS|x1mrS3q4>=QuDH80M-HSTOM|8Th2d9Z9SwbecdeRVTHBL~#Kz$h&R zs*8a|9oR%m`;k0SC8~vNlK)5m;ifcG!whC9q-t;9?IS-zjv3RxNWGLCf(^C>9p zZDCHw7kd}Uz2w@JYc(sPV;{(f_O#Uh+ovR ze-9ta4XXThf-(-wYVp z^w!+Q!s=ScoVQnt-}a1A;{1hiBz||IFtr+i6BQgr+(8wYGq*t_P0YngQ5vXeT&U!8O^C(=qTCc=7T*Z6?f*udOKqPFm|zx7q|GRt03duJ8t;$U}!G zU2dre46MGSX}W!jAYy%AAOnP^WmZ#YCg?9tv-xuZ5HFi%%tDgs3LiIV6yAa@hd8%P zqqpg}`MZW3;GgE&^lW|-1Du0A9?0Hx)VYH*Jjzgvv{H6c9}DO_v{>jw3&3XzTCaU0 z+*l_VeB*WOV?$nAkCB3Z8LqHLUZo(J@To6XWq*Pn;{F~NeJu+BZ_0G3*j>20_k4No$Nr;PB%VD25qyVCa7j6O8(Zh_+T$S(dNx5U@u^lw znrPynByC8n@=omNcY4G9c)RYL(+TFOvcxuUuc?)09(sp!It@A(C7>%NvAdi=v?>&V z9F7hO7}23pane~5I4P;erOBBHv~d2>%6pY@x!^fC0Bu)@;m;7zp9aEL5z;_;DL+2n z(Uo=Jt{aNFl&J}bSD@#Pcv^Xbm6elZd&fV6DlI3CG$n#iH z=zz*pMY9uwCDf2%Au#fPSIFLo2TWhSDEP`7Opkg9jIZcCSDBcX!!7Dy9%Go8w2slf zToF2~EE~Bc1HJH%;f}c?rPjCFbOzpWpmwJw7m^eZ##zoQ$yAJe$nZQ)c5=peSI8XS z%kaHu%m`J#PZG2MucsaKREBsdaB}P=Vo4k{x-(77uw8YZF0fbVAYa8_7+0#7XWYuD z{-kP$nvv1?aF%D5tkDf4 zXoC-Cj`Z&^BY((wDBiaL?Bl$g&b=&EJtAo9bId%Ka*?_bTc$uwrFrOpi?-#`%1Ihs zhjVK3G=0qTYWWz$V#f2^K6i^THDdU`v_0c{#k4Y46(ZmbhaFJL$+i^67 zQ=Zl9cEVm{@{HbTR6c5>Jj#pl$g&guyyiGt9g01Jz z;V{^GGd~L%$Ic!7)!{3CSl{Lqu+8ag7=;N`ddPi#$*uK)07PUQ zS*ijY{W&JR22O2D+h=8E*n}Nl6$}e3igDhUxSi{Hq=E2}RuN9X!sTN!3q{g0B7b-= zCC&jR--&f&Fp^vNLH7bxSn9%{H0di}Ac;9-XbR*fNF>{;my!0(-sL_#nSye;qJj_&}At2AGcI_xO##lK~e>=zB~;4)nL+`%3szLm z=<`STS+&+%=ZjX*XH0NR6jI;4qBD@u1A}j5pX?v}ixDH(2TF%QtE9@AQFod$O6PZo z!$}k>Nkuvp6!XNZJ2JI7V73{3b1&M&ZaR4AcIM~Uar@m?#KH=YdLaKdFgpEwkLr(x zryFYG!XlWW^MrvbI63?tJY0js3DK&d3$@vC_s;WG0%URL6?$E;!w*op!+ULb)v|lD z-mk(%r>_1;#^p01mRUjMf0Uy-U^zba`DoORkz(-k& zIBBV8a|)A+dR-(dKu)sM#*fmdNM^j<#)re#aGeK!B*CQaG)#P!pQYhhX3SZrU1VC_ zq#u|gX5>1OqCBy9%xe0C@kY4OAAMNH%M@8nM6$G!1MzzN5eC^Lmv8+_=ClHfu>qK^ zH(Fuq&W3~g#d>)MoJk%%z7KK?)DG`rkGPk3-F<@sAI$F~50A>&I&W_~Q8Eg+$v{}T zF?T4NkKmxD4AC%33!POY(nf~e$ykWF!oy5H@Xo;+(eg_jj$+(p(zsl4N59xk69Mma zV!uO(QOaUb=J=1-yE73(9h~q>sw`Z)Fi)V)uKETkH^RfrklfyF zR@$4ot{=*mG@gpvS->t^fPvtFngX>lE}uv^$kZ~vGRh>GhT`Bsjmy{{m%RB21(iou zx5$_w!A3zxaa_MzlgY5qlVVyL=_$);LmvdIWn3C4K z5^es7AXjtBq9CDYKTC=^_%L9`GY{0Qx`sW}^;VxG>g@8%x1!}~zer!>fL4G#T2J*o zy3brQmj6;HYiMm`>A3Ogs2mTnt)ZvsfrSoX`n!Us2}QD#n{v>;>B3y#rqG6u%jDjH z4z66Ns$llFVV*Ff5Lmq7X>b0qnX-22m?HDA9ThQo=F_!OlQT*8DBBaOAxU{J&wo0J z@nzTX{ZU=KoVhHNX`fd^tOKoD%@rZJ0XIB5)9OgqCOVa?kSvrbfG1WPH|An}52|cN z6xr^ikcyE$ z-}dL6JGKLu!YBbYaMeM}D5kAtwM_lJwC!sUp~+{<>( zxd`u&nTvS<&FNKnosWnoJ!yMHT)D(Xue&8>dDm1G&xX!h5F(b&+!P9L6U2h>{_&^g zE$uo{ww`o$Qk}W&9*bRQ6eNZIoVzzP4!hNwR%IxHS4D9i)K9L(-}r-lH0^q8WUO>} zoeG>(x0WPk~Yp{L2hoo@^l!tJY053`gDhH{v4h>G#hU9)B$ zDbus%7HC;RXT_#PF-8v$?2A?0P-@px8GY)eys`iSJdO|Qo6ZshTf5!geMQ?Pv7#b; zG4o!gGO|;3Jx&#^98-N-7mOU^a+-J9XC6n1jz<4e$nUY+gzSOeaUhF$dpvF=rj>Mc zaOlq%&6MF>Uo5Xy?47VxYnitg@GSCJ`juvt{SwENhJ2H!sE{!p80st=E^5zqU=yC( zF|)nk1TSc+*J{4&FyMx(U%ieXRlhvX0`%S}HADopJS;tL%cU_n=Z;#ljnMJt{Z9nV z)>AijcHEV2ySqp zOz#j%51z4v4s)5x(>8vrXcOyTv)W|#kMB-Ndy#c6Br6P$GOrpA#`K1591;ntWTCzQ zEGbcx5+1$v$VX(DnJ=y0HMGdwCD;9NgklBI-}(*mWPec=A;^n@+n9-i>;OF%uaH2> z5`udaYP6{Q*5feb&hUdzS+5{5)~YacV4;;MX>Okhb>r;hX7SvQzu>ry+i7Ctb``3v z_jLbhqh%xpni+xOU*0nRo)id-r1NAtV+q0IUkB5wm&8=6NOvGPV!F%l_Y0T%zw>;O zCEBCcVi9ht>ByuUmsEC*76?`HYpSDz7aK?wb}R-ly;Jl2S4;@oCr4O%WHa-PH_?8Az#VXs<^7Kqx-&S13(Z^fAiA`L4 zL{b_{_W>#}tkOy#psSZ$xOY)(0&T`<_I~uFKT1u%?TTr=Q8*aMPnY7!RKW~`#7i8e z!3DJ;>}fj4!u|TQo#-YZepD$UMj|)N;DZK|SR>#bhbcU>o-)zDpk;hzpU{;L$7ofL zN2EUs{2Z}d?tymQmo9f%(aLr^MLw*Zfhfj`B|0NK!x$z!Q-%0=1?ZL4ecdsK`>M&n zSJ7sjBSzOMl$nA2=QSV)CSKX1Vha{7X?nq1h4#)zQI+=4xN2mM`$1>6f9CYRCLSv> zG@q7koiYEx6Ld}4G;qcqQU)Xr{Zs#1nse6vMSr>Vlu-PIEr0ct*XA$LMv#F;3Q!G3 zvou(QsLmGo?IBKHfN}!02q;(c4&dUNm!PCYOqUkIqc{lqcPA@4dR#c6bz$g*P^`YQ zjs}m}V>!hC?}^xOR-#zb|544;aGR9_fj|aoJAtAz0%`T^&?UUk7uM@A4tp>Xy>!tM zoguDnM;Cmj2hee;m?$;)j}=a}jVzbj;)c*tK)_#a+1=v@!NxK`!d~MkcRH!{%-yd= zpzwTQnUJOPi}Ru+!~KvFgod&-d^X404U=k#SS5H!-a}1R)B8 zoK>bde8njRucTpr+%Hjgkl-OOLmtbYPUmIz-^YLca(zNXEyAP=7*(qMjul-gFddH! zo14@3@zx}~bT4neXx)?cw_&-MB&&m`Ao}t{kAffsG_jh{2L3b-{YYdHdn3cz>?e@H zD(O3xkg;%w=GVkyq9`}1?3|RV#T=Q+p=z?U!Z9DnYmmY0e1sA2#N3C%j>tz)mlMvB zsZl|7Z!+cGfmZ(pAdYqZ>=)>3lq5pWK4K1t8fZyF@_KR>Vfn!cM;iIbrdg9G81xn7 z_*~?i<3yfe^4cmTm3i8NL5u_zYY6)Jj^Mwr#?`nOI^Vp3RIp_VpK+*1^Sy}?y4&p^ zOeuVbHJ=bnax*ui4dAbHgsAg~vw?fAJ4UVp3VN7mA$3fS*O&)(sLcIw&M==r#LHd? zPrHk?1`=$O$Jc*pj^A85evljk^1Cq4QW-UkqPg<#-I~= zKUXghgVAd8x~B3YJb@p^J9Rfi-S0K>>Rege5l2aAlIXr+GXv5c9qAPEkoNjHvV@;h z84}Df(Jsx!mlw-~h}Le1cFo*x%y&Zjh2)IkA5#|m_gvNn?Hzvoo2HJH!&!=_At zaar>O%rI!{PLZsE`YgkN{)RGEgq00}< zDZuZuyXh8mzN7z0XF?cwqK*m#FPK|=Y$!57W$SGC7LZI4P1JczQE%2hp-(IY>3pSE zELwjfLcJVSuRwU;9v*f_M$GzcB5V-Qb7FhaCHCmtZ-(x{!v4edcLKK_v zS(pxM@>tjJxO5T~h%V+2vvfG>CNLla1&I?yK#N(B*6M>1XSt)1Yip;Uz&6!a8_+H% zC)<(zc&)q;hM3@D2y&DZ8nQg5$vAJ5E))RlD+FH6ZBH$B{!nYnZ3SkmVJ;E&E%pzYMfO*re z&RTgKa#-Jw*FFE8f8~X`!EV}Rv`%wszZA$4Z;x6vekGrwK~4q^qV~w_>l`9BkSsg| zW^khyO#tjo*Ayf}CD=a%!dV}&6uRGl(`qNec4cAb8Z3DE;qpHBG$S3{%>J{>zF4+H z%TrurE&P)w6yG@Rp;k!#7|DVD8`8iehhW#L+cDB&?1ZIuN)J4^085i^M0dB`T4#^p z(E+7X`Za4S$_cgZP9NTJ%jii6wUdQxcMl@OVAG$tUKw6vZZb}Tg-@NeRB z=eZISnWYBz(+9o}DrRQLskiXo9W;##^vK^N(xV%rzaRJnZ#{No)o^a1F1)((3+gX- zxh)DEMK0L2vi4@0XTZ>asLZu5ykALt+w(kwrhE#HgoE;+OgZf%DfC$Nc<(;~V7`~_ zpk-7Fmuc7V)j{OxW|uQe8fSf{=#k2I$xmPmH!B&hu0|r`SvIR5v)xJ)Z=ZB#N4IXi zBYdEgiV-~{4qR(9y<}r_9jEED{nZ<*!qlTkC~DnQ4%rBXtXmh;HnKS+=<7^M~qXvi0?*5cZ=Ct)<`0uR2zef>~_P9Yw&;vgnc?jO^ zN3AA2~YbBjbSz^2dW zd6SmtXV}en#4%UT6SK2+5s*66$DuhQ6Vt=>uDi8JGFk>CS~G0#uP9k=c}~>f@x(aG zhlt(c8WIHFnb7qyTobDTEcsU7ywO=oIHV<8JVDZd6XC{Onv@9>0u?HX*|qJk?#g0Y z)$JuI!^m_qW5>Gze4h)jF^?|R4CSR-I5361B@M!sHIo`MUxR_6#%x2~1Dqr?NvQRs zURdtk8hus1uAft=Ox#snK!ofp~r2elo}#(m%VkcKTg-Of>Aat;q6 zKlAi#0XJEo4!d-J!CL!4O#H&4eLYW`DnuQiS?h^|^HLKax)-OXMxQ@7AaAW`U z4dpY3by8|j^o)(<73D{j@vR7?B&|1ta90|o-({eR55Hl; zhmK`+c-BB;kutveO}XNR@pps>u{!yXNnhIyZgIJhSoxgZdIam#n{C;UKggZVm~J`L z5C00{Dj6Omu;}xuV%;7$+!muF$0_{6CoD1ZoIfGYj&$4q8DUr0Pb*RikGQU4Y8_>V zi#;so*jI6N409C(rwY&6s!OiWv!-GUE z^i>Tce*k5=NH-c+&F4I}W?tkh_4s0YQu&2n%_Yx&s?X;FM~_<$sbB(ko%`pNwFS%M z7KVwO!G!qBn+oS1@3U)Iwtg$JrDsX@=BaCO;4w&J$tb++w!0Z0t7Mk>}c8x>f`w#5^LuY@({HcwHLiGjnvia^R4-{YxZV$&T}&kfw5{M^`}KkTO{V?G4IB z)#p5po8{~-!}*JZPjQ^%S<{yXn`OI`sKHuRX+i2XD_PPx5iX z*X_fkJaNA@rE{=^%UKC(bY_?=mf=4c4^1xgDFswk#rkZY&psvB zMN?kai^5Q$h{~N&Cfhr`#61ChYqb}}yMfB=u`C1@!=_4Hvct^J9adAUacD8?2km2m zYu0Kmh)vcg@!Hl!*g}r6<*)LqQ$FOR&>q8}$LR_sg?;SZ!!AY&KDK1pj)_c7R}&WY z!t70yFh9OHZeGe>yu&Nu__%3LXI6JLCQzb>@=g=#hk~8kanP5VGNq%@!YrlcKm+%~ zVK`64%qPQo!F61Vsn-9jYr**iMV`|-6M;Ld{i`!hW2?)boSUb_UH0+yPnFbX#U``*?CYj*`9vihi-Ivcait(WJ53y5^Acl*t2crq?XS{ePTVdm)C7 z$ZbsmfNDWfVF7?y(Z{0yiBk}GAiMvG(}@ENF&vuu#N6DPiH8Qs$%Hch^ZILJtdTJ` z+4kgozoe{mSon}9YEv9s+>k)S+tj14{9fFETr6F)1T;pg%z=4r@S9ZX<_;6{)(_^G z#^*sjoN)~d)>v)7AhI*BM}vcYflPz zQ%$K4Cq9sxZzDzCEhi97M&Krfikj?S^Ygka#R6y{Ntec62VcOI8+c?6bP$0!e&WbNs<^Sjc?0vy6BaMQh z1AwAH;=uucA*OHG|A{YTE#T?@jjugNQtadVG=$nRCXejb{PB#Sh~>zWB0_tmW%L!> znKOt%y?pEjiFkb454WWoBnJ)H24k&cBpUrFa3C5-T0WZ6k8_??#BBzI%zG--9kO%U zUTZm?#n#8^x3@kUlIc6{RwQ#1q#M6~wqgq6LhSRqIHh(Ix%m!ox-lGss&E3wOfxgt zBGw6Mq@bjcK%$XOr_`aQ)35s%(&56y4ha^vUn3Dnh4U$+Rt`_t1;a(UXIb@b&%-?C z72PK~lWm0Kt*C@2v_eumcT(~^^HtFSHG3U8)rmGk`?#+|2jG4Dlg+S$CSQ@6A9E6A ziajx+zdRsYhoiN*bnX7Vw?jiQB;jF;6ag(mY)WK0s^-5z+?Edss$N6UYe_W-WB4>W zGBJ~liD1$9y}EKTr60)i5VA-m7U)o5VjSrEjF?hLE6bAdf&iZQZLoo&>-uI=%N3^? z_NwH;nG^w+1$)&@8@%)u~hK zZstjQ&Iq&Yze?2OWh#PBx@Bw^;V^G@Z^=T0{%Bx}-H}us6FJ17seR~7#UpGHACUL* z6?h;>{6^=)!Y|{49H*Bb&wJ9%0Q|w{FFQT$>J+@Q@uIaSDl+)<6S!O=%-iHvN29pP; z792EH833X12yp#9LvEQnhh+Kb#$~7=`8352Z*aj&8KwhRI`#;44 zd@(Tp{}vAwF!OeQq33bF*3o$wG~KFW8=E`Bu47ef2?dwVk77w6=!USZoGA6BowuZR zBm0roOw2Kqol=AMfeaEhq!LT|pF!K^%N_KP8<6yq> z){eLDesWTB92Zkf;^4Fsp1#EM{vr|*5T{*Z)aj8SB zb}BZz+$rnz4AvWELqcb4cPtC*i3JG`)WXsh4|E-<8RU9{N?Z;7JluTnwG7F9Jycpd zaa$L=4V+N8>`e5;#Ra;tNs*nkR;49T(Y@R5V-$|s7&*B)wzy@h;+f74$H z@c-!jGYeS|_5MW`(b^%ji7fZ{gN#*R{3Mj57vdNCkKV=c=0>;>z{s_bn(`MT>qSy9 z+ZoNB+Yu&5lO(0bt8B1%RmIT||Fg|wt8L(N-8$5BRFD{x91 zj!^}3zucG2kDLLm@0RUxGj}D1H$cKc5apVsGf^^2DP{k(ya6I-Q>-mljol>)@T3#l z>z3i4EHrMR!#&?bwi#LOCD(oYK;?FLvR##f2xIkP=4y`3!Nx?n(~!_moSV z%WGA#zmV}%Ih>yKqNEp4{1Z-qzeH=@{^uSe$ftN4lgmn13uk_ z7JZO#aS9$<`XzA>Eku6ziO=nSmb`U;_VtIM^Zviu2ekA*?a8n`mis9LYv3TL;<%umn5~NDom&<@{rs8+dru$Ys;Hw#XRVio5IG`S z{xd|kN73oPn;1Y0ZD9;)6uVo?f>+7mu|e#PZ$U>wrB3MHyV^X3j&*a$);M1Zhqx87 zNob2Q=ZxV*2v=<|ndJIrl1t2PmnWlb9+9e8lYm7c&+Dlx2|%tb^Z->c^E16Y zG=jn~fp~=k232`u)v54x=|sWjJA=o)oz(k-XPmSst`n*El;Iy+M$2m^L2t8z;!2@# z&>*>k8H)o@m~7sBQD1wkCAYbFbc!NF2McIMwrkSHZ_V#d?(wvY%x2w~hyUMRYk9%pa(>ejni9EQ` z2^Yo1$zrHY;b4}7BFyFgUrR$bmpPuJMX7HuTeWka%ClwP7QE@JgG1@zpyja z&i!VDT-{*yW!)-9)CKY8549vW{t$Nws=i=sQSBruc#a2NtALB{6E(~+r zgVS~7q=UTpK+~vgHd-9b#?HFbdkFOeq-r6mJ8^}SB2_H_qh2=NYVIRb_0s|j=Vv>J z1CkCZ9OV6U8=(C!*U0) z8uu^t@a}v$@7f;Bq zBmtEee*n~=z?_@Qx^m0v2wDRlO1|de2u^hW)=O@%){Vd5kiX=ymKG1E-}TSLDdU5n~N2@2Y|p?4eaFOH|4$``a;pSFRLPG&jmdFlTpbQ`yFPxyVz*dSb6Vz3z(B5$(68)tF$7r zmqZ`E;Q%5HCSge`FL{Y$k1g-)!1>FUqRIoUd54t*bZsRW4YYBPpB{;t)|{tBt0W;g zb-MKOk2Zi6SPB*=G>JX<19$$_c8Jn$2O|HdJ08@!iLXpXp<+FhyPk;JEXHk-I_3FN z2+w`Mzf%XLgpFYOW*?vObTs-TQJ!Qt|K;d*1SNymqMpm;SjYvn#}wygQ!7I>+=Wtc zUL{`u7AwjAR2q`_FQm@_03h1ZId=ic<_G}#gbJ4c0G8-p|F>Ex$QC^Nf69*&nFne} z!Kisqa?N20IXp67Pficy!`F>nCvZ95JI?Mk+vEq5QKJ&2qZex6|9R zhDVvFV{C1K!HU&_FLsYKXvWv@0u1`5UMm#U8iqK%~oKjdj>*YELlZ*0r6V z7AC93yON-dkG~mTa5Q@e)8rF$W~Rva3DC4c>goLR#oKv{B&XKh2A+bo`W zt$H=)qE`5%AEyJDf}lVWW*OmEV>z|>X`NU8VGi1aNsfq*@mgYTI9NIPzvoL-qiok2Q%zLQSi>jD&}Cct6{{%b}b~ix1=V zJ~}{^+-0B(s8~k-1p^^s_{^lCRJ3u#Q(!aWE#e3Z$zhqol*59$lodw|EwqQl<;wDw z&+JfCpJ{LS%I$PYS2*C~zrZO6Q-r#A7eCYm;Tmak%kGPK_j(Px`pq9uqQBi0SaYjl zUn*RxD-dgN#~(e-x$kY5FO{TFvdeqZ9s5BvY4_ZHsS#FBdUojE598>BfD2lK<5}4y zBP2i9Ga;5bsXvpEi?@k&epHVZMyhT$V>@oBRLJe~)YYHic(2DYjnKkt4x~glfZ^XL zZ8A>h;BY5Srr~OgDAvBK-mEwuc<|iW4OS)XxCZPul{%c{DaIy}UQ=6O6i*9pxTU{7 zlDEocCe0kk=?PocyCtro)2swZ{?&QH_8|CDc=B2H4*Yk#=LAfLDDg|CEF1Z~wQ(58 zm}__wq2M@3>1{?dw@C1f8%x)(ThYV*ull(LirURWL9?K+K^Z)ru`Uf5hMr7ay}>~U z!dKC@!iqdzY5tMn-Ung{dp!QjM&PbHFn$EshQ^-6M+`J?L=dY*>h2YQa!VXtL@}+o zN-SH{B^twIyv39wLHF4i77;Ng^Kv|bfi-&OqK?ZXFpU1jrdeA|L0O@|fJjy}2=a0q z+!oiIhB+Lqu5+OZ$zFqHXTi`x3FTT4WG1a1ry@;xRwfaO3RH#V%-dyrm{jF zBEFzCh9C26-Pv8ob;a`ai%r0DOiOxVh5_`rS5`sWCpn~}$W7P7JZt5!E*a>(PjAS| z70T<;;s9-BOCYes1A8IjMCpC9*n9!)t#;&qh;Fy@fREHABJiT4@caU2G^QLB1A4%5o~$@Z1gP@p41J==Bz{D8~S;6iUkZvs-CEEN9Jk6*%ruY zsV1}_!nWAy!++gha?86{A3~qD)PWxvn9{oNq+FGt;hp?kvo^h4000TYF(vcra|Hm@ z4tE_444{O_`1ikf|9y#I#K!;aZHtNV@q3V=sz|=uN|Bs*-ulVBAk?oQKP!m%O9vao zZddkq9-4J1BOUpMT_w-cxQm@GOV33M{^<31!>9>8=0pU#tdy((;<&uZv$J~;w57># z`Q9UA_bslUF-NQ;u}KeuA8|_hk#4N`On@7Uz((}_1YiZK?x_oQB=h6su0%jrKTaBQ z2uk{oq2I;L#Y$E@Yc4z3@!hZRgn$jDH^3ljIJ!7mir62*fqY|a)~{)sfQJVnuwurA z+rF1TH?F?k<=&xxPIz=EnqKuJPiEl1rHcb3OXp-05;SPlxIuD=RB{9+iLkRRsQfHs z8~>uT5Oe*rxLCH&{}w;%dQ#f|9!97=eXISboc>K~2BKCPaiXAjSsdc|ubJ_#A*%56 z-^kz&9bEOGg`Dj$ctq`SJ(WEbYDBmZZ7jW+M)u2#pp@gV9tj*X)SI5-!%5m#v+hS> zlHl=-t)lu%3^7LLpHD7Ny4@H0o{g*!Si>xU)&(|9$Y1hx*Lp4ptMS?uDq`?2&<0eN zB}k<%(^CkyR~23A4s+KfgYt^cVpE5H|wfRJ&@>MIxFQaAtCcYdTT&A|Fg+(WjuSu=|<<$aX+t@XA6! zd`d?)t1ge@&g7(m;pqMx`UF+YvZECf;nk{ zzu&}6i>==(YzeDB*;yrY3yA{~Y7xkVwmDQ8$4*G|dGHT1WF>keM5<&|Em zAkd*@Vrr+de8QbaeadwGc>6{H94LN(oXW2L5XYS#ft7>0CCY8K0&C0PaAL3bFf+m; zU-?em_#-5e;KzZL@huvL7f(g0pr<#xO7-m(%}(n+*fk^@0-%D=#EiSXtpQ!GJm2RC4WJ zk^gyx%SPj)Sz5NJjj7E&hPl-Y|HY2xkbs7^?7W?EiS65UmKf!v{@?F9MQ_6qudzsO0y(<0do%coKXHw!u%4`4 zP<#jL1|CUrupe2N(B`p~=?itsw2=}pgPu<1pP5khxWlRG?Q;QRwhDHw%iS-TIUxHe z2ZJ)qVfEQW-3HJ~-9xS@3Dzsjyu%U-sTy{TM1dM4f!iG6!pZ@MiY>R@;e#VCGzHVq24H7#J> zdG2=vb`eXRE@Ne zGCwWva=b5-u#*$X;L`gdW=TI?O1c;SZ#j|0s7-nT!6k zo`LSVp3_ajW?J;uXS@!)$P}U;b;Z?|NQq?~8A9REI#E3MuDCn*<|M0Sfc6bMh_5{j z7pa~WD4Z}T-cba3JPFTeX8NLBZMY5B^t!|J8%-N_XM%^q5x%i5Z;cV7k?J9_S?2Hp zr2o1{Mlk)eD_lriYPxAO-c^Eq_wIQ|{Gx+~iU*!WCn*JC#t{D){6pU0zQMfzBK>8@ zz?iUIQTRRsN^)7UZPca0H^W5i@t2W45ZTnk*&s;{}Lq$q0YKl zd!Nlki-*mqw`CZ`+&ugHvm ze}-8Nu_YM@Xwti(Ksz<5hT`xRZ+h*&-@@^`>U@>d`VXL9>uNY@!Gd?M2TXfNlpZrHPkIMtSDuZ)yd*}_ zit09MilTu5FZkBpS$h8KEjrLx8TFepBXPtoSs?Ocds#$TNiPherROLOd+RQ2pB`vj z58{z9ew+okHw`-EiC-XYG_oCyxn!;N+Q&X4v-MrY^*CHi5dv}6T+*Y`n0ljMlQ!NKp9r^1>Hf4^qw-J%2V9V^@X zHdguY^%5E5O&08G1_5`EeLdA4gFB|Hp_1OvX%pn?&m}4SO8Eqo=$R@OR6CRIQ7)j; zo*!7=S;*sI%|xR<)NYfZxXHbXyWdl^Yt;0ydJ4lOQRi{xS%Xvar2EIyb=N9!pk=^2 zgY7SKnPx$TR}woL<=5`p7_Zmm23moOBL)9HL-?OmXRojujK;(za_@X#tT6o!N#`oy zgR0Hq^ADafEW>BfCe_q=i~$u-rXi9^Xxwvt*r4E37imsf-mzMAd&k3{IC6 z6w`6DlA7g1s>ACRi?18Ms#`ZIU=(Sb2}b27#8@f#gH;$AL2EXkICl@CEvz+EVbK-Z z`a_k3lB7^9mo6;Dl9rYffdbPU)Un%l& zFz@CtD2fQdwAcIdBh zzvxIUO%uW$-7(la3_54p*ybI-gq{vvm8BECV)qwo0$w}4jjiB zPqcXj=fF0-c~>+ju}(D$V-imjH74#LXq~q*M2qAo5j%KV^v_R|ku1J8z#txf$c#kW z(aMsg_}r8~;k7zPNj49YUbu&Cac?%kG1Z-;UamTyCH?+C#;yTN6lF=aZQHhO+s19% zwr$(CZQHhOTk~cIe-D*;GNJ;(>UB>#6H046mH<>~rDa-!FdY77GyWQsk{-dyWK3-P zI>HI0QY#lLg#3%Z-2s5exC%Pc?VK(C*sdAQf5KV)>ij;%h4g~-mynNO{RTQ`ZYCkH z-{I+yIB?#=%I*L_(Pt=yGVCU{dg;SG$!&3yU+2P#t`=FZCBjq6Azwe8$%$MbtZ{+E zH?K>!udBoUaj2PaUlXot10a+A3D_adMKFd{G=+d|90op0jSx;*blhTQZ6@qvdg=lj-(%9g>d~)!C|Y3I z72=J(o2+2u4pqLu%q%`3&cF8Ej!um;EcGJvt^|(gINo61s1)Tt=}mjuTskhrC~R9d zAEgggfxfm$nYw`zHR9;mGyg5G_avx_)MR>X9lSFJSz(!Py0YOt`hWus=w++60!hm= z>;@WfE*&2G4~K>CLfcV8GhI|zlbsDY?~^R+f1AN}X=Ixcp4Kn(BDFKUU84B6aYR2q zN0i}93)0qmiMNl|Kxc^%Yv2tW$od+5mJyTes+-Ph%BceUs@0-VV<*gruBr$ijp(JZ zu;0*OTLiivXTG}_%7O5TPv54%6i|G9-+_!__<2f~uH;p6_9t8<@#q?jBaCM9)f;H* zLY<%8u!+u;tn)8Qazij?RfCJIIGmeOr`U$9I{Nc8^(TF^Vk5py@U)T%fme zt9l=$FfiMLo@>AAoZq*CDRk^IcK9S7JivqJjt&F4VcI(g@W3ShT>2D2#F1vJh69Ye zaHX>`{lO@BSn^ zpTl?Vr@BD=zxj=hLiyXKGX9D)JI>)KA6qm^Z-Gi2fayIcK{R+S^L7C}b3^f&Jo?Ut zBl11FJiVd+(_)~=n6@W7fkcrngZ+@Cem&2rB?$(s`}WU~!S2?>6FFqxk@d>sP=4tC zrI}2DOQ-kpW`nK=R?DdL_ZnZaVS9j#jtQMd#vdXY&pgnGF++`d`wZ&EZ^KeJZA@RYQRHXa=W&HgopsU0cLm+E@v4bD(+!}Ve_{hFc296qxP%&6W{EF0l*&Mku)Y^V}Q%D zxgFlSn`n-r%-OZ{3CoV3S%*OWHiZaI8WoT!okwLyjcFL`JdgcfTH`~IFH)}TTTiixqYSP(n>{me5cO7^?|YIbz3KA-LFMdslLpm z=p*yDssHT1SqCjP6KormSr4_nWVxI{D`zi#X$96I;lCtq!^36^GWL=PoN{v4Pcadg zB)_z1L%=BdrykP&U(?yM8)|0g1+Z6lY*<#><#Kj?gh|%jo1pda97XgH6o!Q8k!DDt z*i~>YI2l&PD2u-=SRTpBXy{qs_S18m-6QoWT;iPWR%*8l1mNd+Rg%6bGOpqvBG{&%{Hp z1_4gnDGt_Sj+Tr@onuuF>-2bgJrngnZDUHCy9_nmO_9Z-Bp`Y`*yc#`S0sEzz^{2b zG8y?IZVAX=co^-=9C`1P=G=6ZLeScLe)!|lgg#(iw1vVcq>#0t6Jaa>*0vz@ti6dT zJ_}74aiu~(+9oh)WeUYxOPXT*NuG+}B3j5O${zNO*qW&&+|U(j{JSx$y<}4+?$i7L zX!INx$oj4FjAv2I9Uai`t#@X@auFBt{LmB#mt)Uup!XpGuQ9d-?;(&1LY~hQ_15Yx_N@Hji@-2|LdD#7#t87sKMC z3N{@zpHdi$Z*|0;)ghosxL4;b>M`qGqxhaj;q1&o#ay?Go=2vD@cT(1d8WXALQuriKuPU#{^_SCBr45y*7o{Exo&PC zX{f2%fJ-N( z%#iqFc2F7g^z7}&X(R(A+R+dKSb7{|nNe5E?6bpH{xGFT`WIN#g-%@mTPsPO?szQ@ zQ+R#HWC6Jd^GKlTA3}?QLN}9B=-l$TGbA@l}PX@$9TIJ8)7v`kY3a0Q#yBm^LUvaF7`1WZow0 znC>9&=oR|RuNw{RSkuJmY63oX1h9(#qJqbrmJM?gUV<@cQ+*&oaXL{~QW>fPQ7eG^ zOPf<{bqX5L8(iGE%pe3a1iR(vwR{#lUUrS`r#41W5kP(kX*yLYgc@eHg0~F6}?ZU{>(u~IP_-v*yuCJzv757s0 zXo(|39VObw#-Jm=;}J@Tfc|)Q#k& zQ$+@@E9v+VzN%-qzwo1!#>&sk_!0Du=ZJ|fhV@25VqB)M^>w`{WW&;I`yPAQMPYT= zG9iSl@6=NWS*Pt??^~q7L$ceL~2exJe${x(p~%$L-w;~AxA7Qp?XGaFsEpN zrB@8AP%6DzOl0lO8g>lmsjXtJC0h>Tj$7tsV6*695kxD;udWBc4bl6-QRaj=_r^f} z58uL=rP|C6D~P}>xdqGCbi6GI2daRZlPHtAlkphf0mKb_!2)vPVOc!#p(-eOTSfOS zhueLaUWs9^x^=mE=Y40CzvphcuZTi3GlmF78>nz++B~-M0M4^iHjnjsY$AJA>j6@A zzTt|-z*cT7TXW~Kj39c~X&=eypR>Wok%?tyDxID~$1i_*l8mZMnY#lN>#c}39`R7P z9y|{o^qA2i?Xc_5s6#4s9A&Myh4s>7G?}DZsL#_gdiZ%oSCFei{sS3{dD-nll zt2P)8C`^n8B1&ao%Qe`PTrQun0@=HsGG-d~z+^%6-xh_Q*+l_b5mGRFa+XstI4+T( zji{#EQA$w^C+3*F;&eP*=-1}%&TW?{i!iNX15$b^+3&p~N!0*`jPx700ayMMj~!xZ zao6BPb^HY-!tCZTiY+_VRiLl4alP7vszAz~z_c9^+Ohb^4F1H}T#hXHMY`i$xyKnb zYsOd9u=K@H38r7qigKGmOiNQS`_Jih%jF7}iVVXhK?*9;JH7Iu8AG<@K9Bj%qM2)HsNYR-~{P@Xy+$s z!Q_m3;CY5nYY%ln(HiAlAl;kb&|?20TnwRPNZd#ME%XC|uLW7MUlgJe1li{)*sgAw)SbNUt&#ik2O9ob8DyEhU z)!rl!TNp(4Aqio(_Ks*rC^>1T@Vizf4UY@&sa(X$1qg0<16B(fmqCo*)@+0cE0Xbj za%jcL*lG7&uzV-guuP_*0Qle6j#Aof!P1@k)L|n8fH@K9@;6~<@#cZhTK3gFp)f5$ z<7muRAEUfbQ1+cH>aj$J<)lsnd-UX&)2N>$`IKV@P!(T6CWueFgxI3{h7}{1t0fgLn^d@a3zbkFA*I=JEsGI3ZB`%GJZ5 z*HUQvt0S~4_3L@vj^+D!1RukWaE5?-RwozEJ&Hzdx+$+2m(%{>iAHwPih~&iCf3^q z#}=tQ^I@YdaHngQL4_K%Y4pdoL{vZhS`GD(LnL>$BG!%lm4>c#LTDV?O@riIEvxYN z0H4BtsNgCmbccAz6-Tk5)fap-$qJ%c;L>KJPF)I^LBRQWEiu*_7i|SBC$)X8^R!5* z27^{IVt7?5!<8ei-sB|S3Q3{A5po!ZD7^o5@OO^Bk`=J)8VSokoX}W5VZySv#kZTw zIYt=+^0hNPBk?RW&g;5Z_mddq`(jyNP7@3e;f5x+`S7FCL4DIO6i9EmKY&t`|BRRW-(?mq1+UUHeKlqg3H7#sTh3M zGc%e@K+7WJwrFmApN#`!I)Bsa_ZSM!jUf_|E0HZ;M=oq+x$|L9kR;#JbwP4fORpvk zW%oe!SQ&W7C4j$EE^@(5z2y z$Czj>5vs!UBxbuGjVQ??)&@)f;viIT(<~axMKPFV6-a1vi`8VuV>0JOTMa zc!9bE*iLL|J7)=%;KCW?d~kQuNPR#~bXR&gv)`p@T)RN?H+A z)-c^`&8+1XuHnJKVn|vmDNS12KU#m`#_A;{mOB%a=eQi|m4HR+W!nnHl>^9QP9369 z`cSvf%phb?qzY#d!FXP`Uy%4qG!WF^Ah?z9_BAefn|m(YY(sg=8#PL-f$MdtYc-Ix zX%@WcF#37kmZyM>=mP&XuTmA};Q1tV9A)YBWZlbe!d2dm#e6I%+3o~W=#jo`_$1aZ z9BaQV6UTp$%65tX!B`vbsHyZx7ET~l-dL`IqT5n(k`0lfk0mL}N2?jUtiOIWF5KdsoVj;`%dn`wX8 zL@~vhx~nqz)8woIZahfjX^qu-f?8TDpCEp&Jz?CKx6c!?2j6+jw7#o1tjNVH9Y-qK z$R*Dmsg*HBxc@h~4Acz(d2^hEFe7|SSnG4>hVfzyvEC=mqX9YW!l6O*Ga#b9$|ge4 zd{Z#`&Cx(E4uCu>{zMB9TRZQ~hxfc+6N~ZycA$=*-<@6zSAdSg%JEUClgZ5UHr7C? z@5q3C_N9%k?`;Kq+K++Z&Lxj*O^=SG;X`+5MJKdW8M^sB|7_yWqGr4?jHo(`?yBw{ z%|gxBygz5%;osc1>!;+)Puz+28oMhl4rl$(^r=uRx(+sxfyNK4;GlARi=7k^QjJFK zdM@}C3}&}_Qsz$aD@;dB{%o}&ghG;_^9mR!1YDQDk2)3xH;q%bbqtLFWSm^sw#beJe zoXbYn7M2hL5Ac2tY{no6u5k$_%N9_0HlURtXXFNYytlbaNH$0q+y}K)HhBIazhCaI zkJ<@u!=z+uy~Hkm=zK@OSPQMPQDE@+X(S~fS@sM0J|UulJmONRO^~cK`EP+x zRnMwqw+~EOS0Pg(FR3FvBDnOe?otHtq{iB`@cD@&v`0M8*z~uw%qn!Vhb3-*S4Ya5 zHH!ARejpZMYGxL%lc5zWel6nFHsN3F3cA<>9z{gKU2=vt&go%%o5wVpQ@@gn3RWE6 zNE=E~Z#OePx#X4p;#u7A4?S7e%7Vz355y}tc6C2fh-!OenMbM_aLGm!~V+r#&(iMxU2O;rpzWM1N}cr&hszH`G$6Ai)KYlKM1C*LS@EKUGz zcjOZjt!79*4*v1cM5$F#_o2?RBxH0 zUXPcbgx8E(%A^)Lac39x5@ugz3Y8*Up{`g%qK6TldnuB}J#+28l^bLGIj^B9(Ts46 zQLyL~YR~Q1$bJ5I9U1yZoU2lTPCiuf@90qKt$sy#guJw(@@`n38zCYn$Vs0ABr(4x zj(^ZvLp@mJk1XC30o+f+bloQ(4pka|LNlV-+}eM#Z@|?gQ%Z)joQ7AJ%}kFdxL~VY z_dWjr6jlKM5vI(^7agL13g3 zRW$xP<4aqvH3+R9(=K135abA(2!37SyE5+qwY2gA-$LQv%n6LHdh;fsX5O19zf}%V zs}1ndTuOGDVayCX8T=x}EocWT4=>3P&AMb9op!Xz%>x$--nJz1}2v(*Q<%L zTE1LJgYikIyFk;e#@2^58HUvSP;~-9l(Jfut%~p^Jk@Z~@Q;VlvwuVw`;zO4Z^pnv zOW2IB0Y_@+4Gz|-?twL+onRn;lZkS6*n$DYJ$xdvh$6_I!DM8N7WIfd`dAuzIbR>> zHBXHl1ZO*U?7()z5|h$B2Db?q7)+qAdvI9fSr9;SKX@?pw8finVNZF78?LJB3wAP6 z0z_YZo=_r8ox_#sz%2Vu2=?G*&Pq)fdSL{D;S}I=o3kX1qELiye zgq^dEkzxKP>^yn9sqA%axSVej=uE_nb*EX@aeWh_PNB+Q^M}M8t#+z4D|Kqh3-~rh z1*S8?o@Nst7Ivde{*Qrs^ThvW zz|@qKLm?^S&>h>v?5SIiX3nfvz|1&>fiq^8kl?%*}T)W z?FJUNwlRe0n#b?%K~)+1>x@HjftQi+SEw7rQhVbcZ0kqT>kk&c$^MMJ}s_^lu({pN7*##hTMMv58A!~B_TKQ>WV?|H`Zj@ z>$1=pWdXU%`E2uy^)rE#a*>{wxXV`KWa+`e)e`w5morlhslRp^We6hS7X%vG91G{+_w{#b#llcp{R)pwy+3kl94C9vft}u|tbi7PR;)pSrsH z-f-OHXaRYT#CB#%?n&%xr0!HCP7dhgHepHmKYJ4r=S%dwr?8qsXLI1s&wh(cnzgB@ zL^#w?Bv$_4iBMGE=Gvnh;Tfdzh*~2-eDQCB@iaISx;5Ne;}ML)cNVO-pElh#-K9+c zcROVn; zG;f-pK!XYf(ZqgLM99NBQ#1B_pSAs$dTx+QfO40oKA{IEj|1dYR}IMrwS{j04i3W)}uVrme_ZbU*1>*s<4RME6hAGwZT?!t0 z8Ld#Jo{ECr8|t)CDL!`9b#-A_1dB&<_sxQsRs2oZt#hw3u$MK7uUF{7U9x+4JGxb& zFX*b~5KIaFxtX5q_aXR78;v>u$_Z#%f!^+01D}Qr#agD^M4dF>k!MDp2QP%wzil%Z zC9Mb)vKGC;!mx(g!haeNT7N`4(7B#}E|fp6FG7{nka4X3A7dIoU4J_IwJi&sc2#ET zP8qjQuSmj4me^dy%Qh-5PM&9sTNpFD{@SdcR!_4}qB353y@o>V0gDw&DjyXZ_KLIP zF-uehfk8s!iJ3PofLNnk>(zy;5_or{0&$-`IFFJYKcmUOYxCxU zFA(0=HI^;v+wWBp z0xttcfV80{7Vve#2I*y;G2fE)*%~gE!qxw6hDa&>U^D0RpGy0dLysy51ylr=p8n0b zA@xs;LC*Dxirfe^7^6yP6o)(}HqUSe8R1*-bCH9hT7gN%o|?hY*PsI7#v{bj1;2Ik zxQHpv(TKBEO%}(y)68)r>PQ{CU!hcDOy_pe4rOXtu3?fAIJ~GZv^S@+&_aJu?BucB zbgNVV_hK{g<(n1JjF-?YiC%4m1TL8ym^-OG$SVzHpq&d#NzxUr92Zpt-=j&i`6{GN zX)=anwR#GSbRL66T{ijsYq_X7oBuDz3T%99z>=508iiL}!RlH@85>g)QelB=GDbX} zW#{(vbwM+EP)I1Jnr&e178_do%=l@t%Q+eoMQS#4qW*-D2cFR)SO%T6eyKNiOcQ4y zHkHE45J3al9Qt{bf(;riYz}3TE5(aeSrHrc0Q&HHL@NmAwBH5%&(VyDkK?qbD9XHO zyLM=?{-7qGkSIO^2;MqGV{hWWENaBtt?0Zm{MtAD>KG;^)1+??jw10BML_9miT4i| ze!ol|aMLz(Uda!jnTE5S+@8N&=?FZd_MmEcvcdW3WGPl|r*EnyZ5s_Rz~GUKesUBa zA{=#Y;bW=5{uaiOzSE$ol6fh*`v&8H*_~_)BBX5_*UF&XzaJ)W46z#G@Aq-xbLpPG zXyvnvxZKpRwQgFOc(`?ZF$95|S+*~Hh*L)y=gda^!;X17-@KC7uBsmPT~!tdn00&@S8@Naeu62Mc6G~^XuPP*I*r;>6)8ni3OrijBS(ZcjqPH z(7IeU92^;XO%()(R^i+T+&kKiO!oJ^%)_^&dD#DfOkSV#=TB8jBy&jvO704W&mC3X z7=KVp+#cnMJ11WHci%h9w%Gq?k5ahk(o~2B;J#B(Ae1tLOBN}PzxCWy1_{lu#Flsx z7Q1KaL_KODy=0qu>%(lkE-tc2+6BA}2CjkB_zZ-Tv#AJ!Db}wd46K=6&ms6pH|3j8wfA3ku9J%LQ<$dC z{IhWaJ2X}^5H>KujVyeGoGb%W*Wyt_;jSBVnz0&NOrXvU@?ssaTzA;*@e_Q+W1Xxdf8KL}W%Zv@StLZsmZ<%pQg}#0YS`+y zQF_VF&epLf-a=N&3atVmOgB8l(`fIZ^F3xJfzE zya4PSVi`}RQS)UKDc^@EliDoF5j1NugtaPip|T-`sm$c*PA=y`7H9odU(p^;4L;<( z3Q7CkYnnOnWvLDBLw*-My)f!#0}BJ$N%4b5b+#Ik(+`uS?Pl>LK&YL&#NGERKR4dN z`>xVOl~CTF9h_>&%{&b4KT(B`!DeT@VuR#}jEUGp{y}q;)*q>=bF-9Nq>M$ckJgki zuA7o63wGQVb>J_n7Q;Mi8z-D+u(#kwzuZ8Lpyqm^*u)cX{~PQck~|D~Tc$CijNaIO zl8EPV`pr!46D6Hz%_xIm{FSW-kxhfEq1McgS9AfC+pm z=y$h~p6__(!HmW^6iS?RcA8L8Jk|v(ObDfW6{Nrzs%Y{EyzdN(RhpVO2cfFqT~^DyLKcj8Tbh@RIgq?|@G zLQ6b6pmylW1A1WumA|UtpUmfGyvM(DMtIgjRz`>%I&CpBLMM@yWFk$WnjLv9H zb3I0UgPX-~R1W}_tLI$}K=v;)LvjD>$c z@pEVCt|5gkatn<4KMP>J*|EDGsN+wu92`o5K`-dBkSa3*Q(C5jgmBwaFZ9Z|d*bn< zc{R&DcySjYqG;)z!`VNa=Jn<0#qq+joj@Ca_f3_X{# zu;Dz$GbUof=+1x0!60^L`j`G^Vdk?&^&AziEJ;*V;s1WM@k-Yvq?ivcH~t<(n5*4W zg^r?0g^JX9|I(Q*&{6bt#xsm(oXoK9II%gIi6_agq%zMEr;V5;O8td`a(I$>#qWfk z!Kd_RZRyMDjVN7AjJ5!y4cTd0NoF0K?WA=;#cvd+%_&+sXt|KhE#uut&PmNoI?Jmdaoo7D{uz6fGRCRDQGaZwI{5wP9nd)s*Hemt z=jJ1cB<#cxS+n-6RlD{s$zx9kV4Z!@3%aJG+l2%`YXV(@KGNQ1Z!sEndAruAl5A>X z-_G%9h`mKq2(=@ccA-+!7&t~DOw&7Ug)~w=yu&P#s{pF)ab#o{z5j@90a0yTt?VC- zY9AqR!8L;gVUKrmyW&ll??0Eb${*QYf6vM^VE+1uR7wGE@lVrjQdK`Y3dxk7&5?cO zsiXVd%K!X0UK!D(^Q#RJrP{zgY3%~e+*DRKQeK$Xl`g-{Au0%H1gXd z$l>jpkoPiWv#>G~6iq#@gsBGJ#kXLNWgfcuY-?L)<;W6v%I~tE47FK*Ja9AuWiF&$ znvXhAK39{TBpeUNqqVCDNdl6;P0upPeGFAPEx3(Eg!oCp1={z#PMt$hG&MX@^(y7g zn}|V4b$x1Oe}DqdduW0n1j&=icQLIC&o81sIC1_ZrZ>P)w&r6eK;&+ zMT2JdxJC5dMp%lwgb%>PVdSf{D{pcQ+ zD!q7m%v^%0&zF+6F1Pu&;965a&a~$?wZE zblZ-}XbmN;1FK<2`d!xuKvVzoBeD_^vy5GsVP^}vW1=@rY#wIFh{`G5W{V(~b7`k> za$o=C8~dV+_5ms`eAW3?^+(h$V}+#iaQB5^q1Oif_uPm*Gv0(jH(*knHmm+dbCEyd z{bItfp*G>_k78$PoLlPEJr}^W5T~}h5g;`HU^&@II~c$&2`$L~#HFeCAWHvFT-r>q z0hfmMPUf}m41y*ZwaDWXMCDFOwBVJwd9TCd6r~aq?9L))nV&QIooG?cmv+I0yy%@! z17KS>{guG>QQ^F#kO$laz-wjIx}v@qjvHvg>yBOO?%XLNTOd&^HV z?<>X4&e&{!A(A70*$Mq|-?=OC!tDE1){-}nO1DsDTAx<1c4aOwSzB*oXE*4#DB< zJP|)etG#tRTYJX~s7sjAKiCe0j>rk|Z3(u)E9ChlL2et10v#7={HaNymWfN`&}zLq z=Cjtg!?$o?mAG|imz^J*1bke*O>iONDw7m~pDwn>V4a4G85x$uH;O6f9EjGpf-i7$ zaR^hVJsQhT{qfF{VElIIuYJ$~ZzPUQ^gX*h^Lk(7aGfJ4guFgUo zMsblf?qLy&%=l0q`2%Hbr1Arm;90qfH4&*Id#(mXm%T|O^_U}?r*GNPSW~D{Fdmf@ zxo!6kVHC@KsD8+tMQLZ0)jSQl$%1qSC_w?%*rJVPW03ZR;BE@8U|Rso0E8)w0jj(V zG|ogVthHM4eDZp?m+Yz{V#G^#Ci4j{;fTiS&}MNOE$5Ft*?r2uGpoS8)mucOgygs# zqf47jA!4G%(ZrbAM}T5o5E3)&YLWSlP&Sb%`{Y*eDTIkLahZ<(i?_E^G8nA7<~mb( zUjVBCxJtGlLIZ2)*Rk0FPCGX`%u&zfo+Mu>xR>3%NSVu&9=M_2VX-^Mc6?w;BG9V>L)4DM5snXtuXcSo@O)$=%NIYgN zj)eiG9ujFwDoctBbojIHgK__%*l$a##er9=EkkKM(!geYorTMwBK!;wGP{r1Rm}Y6 zBo5M(Dks+j!0ay`Vz`uCp)952&p{H!KE-X70AExdNt7=Y>w|l9y8^m&0uD+a@ z0IM2b9AD!}EQp*qAih^LroXrDl){^MSr~_IrQP?Mcxx1VH^HiWx=eXw_2))N;fKQk zYs-o#Cf^xu%3`q|%DBkT(O|Q)y*JC~J%9+Rs0=rfc#W~7E1$iNB8CUlL?@}L#fNo>4Z75d8fTklDz9Ekatl9CR!i6L!t zJ*U9Lj7STWfYANs!|QeRk))%$_u{Bv+|Ft)K7788>H|~M)Z8M8_Ji()J}hmny@BXq zxZCpWVuA)qxiNgj%6u7KW4`bV*!_MTN>Av;qGc)3$V6()cVGJl;Ut5{(p!=QS@6aR5xNbg$g1r}iSur5`@pcR&WPxYtdaarncQ$r&X? z!({(*^p*ppQs`{ow&uGP?7FM6VK!70)NQBLvU>Eyv}|Qoxqj^LA+24-(IQX<9v7bN zChYmt;@#l3#psSp`~TWZhX6xr)Mzob~)@FFgZZVA4o$v`RI#?Z-j-N$@Z6MRP&oXVdXUZ9WVl8o;#rUdVTi; zsRF2tl~qdA{96q=%x^w2gWvXe7di5Ev;z!It}~Qs!P%iK7n$i5S@CD(7xZG$?E`oAUYsh}yrF)0Wn~R6Wr96?WP@ z!C+aBv)_%2(tRbLnnPHMcNQ=lhW?E)Q`7&9d*@k$*)tEO;Lsgo?!QK(y5dqtg;UNo zACB~Kw0=%Ve4U3Te?&f?S-)O*+WJ;|*Uwjq(B2FTcq90za zq4jT0W1$3q((#_SL{DbkE?zO$Yy6#WP(f$>L9~eUfL_vtmcb!S|2StVDbPQj)#qB- zMx?J`Q>*OYwb(@G7c}lRigB9E+)eF)V`|6`GocKgyuAqB?DV{-kTy;R5oc)$5NCUj z882qXkVYG}jY6(qpYzg5T2iqGs5*aACT^faST3^FSAM=9ND@JU=dt8xfcrcvC~5VW zkJ-+!TdTd`+qmg1gCHF8QpYX!<3Gbc+`p!pSl(}$LHu%NJiNHy)*iP{MmF6Cd=_)l zxzCM(6tIo8w^z`{KllEK>8Npb{dAZ+<%>xlG%ChBR~0-q=L6ce`mV^^owq>)9kN{s zp4hAUdtITOrS~!hb(b>OY$Y&@S*4wOmWhV_kks8LCD5J;Ji3z4iwM1nZsvpC58tNY z%wd0T88Y#(V^;7CjN&h{1-lag;>Yzcx*Xzgtl2}BM?uzLj11-retEGVE?Vx2lQ-q` z4+<08IjtQH5-}X~JLRJ0&3e6<*eL>PMg35|_;uW%Lz_8-{cuMU z|E1fX8tsJ!eboH5)=?L0{z*cg$%DFf#^i4}_IEjV9}Tx|VJ_4*$wu60n4=-&GeJ0c zS!u-(JgHQTSNSLuhhak ztW4OLGz@o>Sgw|H?F7WUtD8K6uASqgIKZ`%CI^KF03^Z5P=USYbeI^Sl%fhNK~4iaENDJZ5U)1BDw+9%98eE4to+ltb{gM%ySy} zq#(-LZaSqj@>GEh?}6MChl}M+Fq`^Q!($xssFsjyV{DYovhhp$Zqxa~+8WDRCdDv^<^S$*iZU~GDG{VemB zqF)Q@Fb(D?NbV}}>DF-WNEUVx1P8NWKh(}sHSyt2@2t<4X`BL0uA8MEifG55FAcPi z!4I?3d9n9b(8NnF>1b9MGH(P9oUuzDNuk%a>A3V7DmTX;4KW1!X^KcBzl;t#1FD{2DcQLVyw?Nj=cNTlkr%pp?%ISRBCP7cL)_hQ#(VV#`>=aX2xz5`yxfu^>< zBhgRpd3cu_|VJJqc)6!NKPGY72Qr5?ach4a6Q>9bLtnenYOZs z1`lopQbIH7ipfx0sA#tg;nc*8CuhQOp8`tBX;mr+LUsgMJ#=Y1;oGGJV1z)SQxF66zX$A}QWmo4vZG9}n z+9|=>Lm#zsCl@r&qd^82lH5=hDe)n$l<+R_?6!gwuJ*|yOiI-RDatt;Uy*$Pm$CA> zcH+y}jeSra?`j zVFj+@&lvylupF|x_b#?=HD^~JFE(a3z#T5Wd}^YfOUwL~EF*;DJCNq}n2<(fUiwE3 zac8+yb#U@o79jdt>WFkQQrUO{C}RSIly7o>yB2={SB3DvL-FHezNHf{Gyl$oqieoY zR$ydqx47*0$Rms)(h$7bp>5WN3x(&)YiXQW_O%xC=>a5Fdv~ymXjhGqYcH-4eAKXR zxT_?(f-`ru(K@_1!U~L|fAs)DR`!yT%w&#^T9Aan$h+4^y}2<*4qeBD3aoGMaF1n| znK8LBc`;>v-~!0-c2;w}MD8y@U$nU<%j~1)5m>^D0k36-$OuF-zUfsFuca(N+Jvk@ zMUBQF?|akpcP<=9VNS=QYze#!niJLnX5bRbsQgRV+l$U zs9ROpfzmgeaiQ`RBJ1oW6RbI_`6Q=rJm-vrr};cu##dEpypVClIxj%%ncuwuv96Ch z6y4MB(4C47rNAjOi+H-nmcAFq&((ogI$tZ7Qt~dMLtd~Q$_uK9 z{*?A^u#zi^BvHZ|?nJI!1B8{D>`Njx<*2h>bZ-?Q&mW%oU+>9Rn_kpN?h+@di~a8Mh*~={k-C=JI7HUk^W5Hg@blasV~F!h=|@ zxiejU_R8|LK`@c5fa{IWVHB0=sj9gX5F@nU4lWaGF6baE<;$sFWxd=mat^%Xn=Mfv zVS|U~+}&bs&vX~TMpfli|I}O!8aP+6Hvt$N+Y3EFyxwoVa2Ha_6p$xs19ihQVZqZvIEHVXpIk>2COv@fDdC^Qg{ zs$XZO$619C&VU_9cSF4A3%XE-y%LP<3%$vnRWZP6*2R>VNQBv)(m%y(r)qjp9x-6` zWN+pJg<2uPl&p8`Q@lL++&o>7Wdf2@OOo-63u!wA8^O9e!)V9ws)a8a8#pE?jN}GM zp^XuVnr+mxQV@k#KjI0>5*da4CbwJPpMbzPc8y6E0SomJXn-9`Rik5`+p9ObRohj% zADbQpYcAdHTZ*=@Nc;T%n6gFaea#q8Q2>BvM7{N(08A=Zg#XEl;qyZ1|4&}bk=~!I&TK_Vl z=r6}YMeaxC4VT$k1?uh&aNhAkJ}G3@#|9^S*g*~!~P#~U!0c?LuPu~r2U^F+~LLo&h8j8|BSe(hC3fMrGYFG2?OUGoJ$5~hHOD`yP zG}d=ci6sj}_VfNOoTyHyD5DWabAOH_m)+#L1S8+!f_JJpl3VEd zL5E?c@2Ad{yk=cR{rcj4&E@*!_jo`+hQf%Kb97l8?^f zsyZBi?XNal#SysMIaGhUF&my>)b_V({gRb4+pD6!mNTF;M>k|Fd7%k{o0bx0YWAF9 z9f`Qv5Oe}@B*u-=j5T<6jla@{=XtLoT29IyL1NZ{m^G24c&wf34&S5OdmyNxWS5t^ zqy@nH1^IJ}(~vZ_4*HY^t7!`gb{j)AN)LwHsh_X5@M)W(k^rh08paj@q~2n39Sor! z{HE;32TF|PW1Q~N6i(hI$`9P)#U9hW327zA&}{Tv7O1M$DqmmB?3AfOrWTPC_l3rr zL$?+z7bTQi%d5iE>w4JCZVBO1*|^8u0Uxq(=7RCz>a;%RM56o1?1>04iKdgm^%t9p zrp$%_?I;9@J5+Icig*g<*+@K*WfXi+(4P+eP)HQivji(HyHAQ>_5rE89tmoep z=flH6oS+`bJ%_kk-6W65!{!8vI^0kf#9UY-<%F zyYdpQ-qjT+gR@S-=5v}Rc;0qW3ICpdK;m`;vuX;F^*!r@i?g0wsJCCPH_`jkY^nne z(x_9X6P*1=dMdmFC4rzX9zB?iC=GDeoYybN(Tl9f%P}=hPvN~0f6|atNiOz$_cuq^ zfri7JtD-QG5Kgwls_%1p=KuwEgWjr>(n%pI7=zVHSqU1e6&!VCGD7_s!sARx7pJ6- zz3rL{rf{Dq{;iyMLR^OBfS6xEg`4>96KjK2x?3!brfL(7E&Ud5yA10 zUGxOb_Mq{pU#d!aR#rI0BD?Gp?sPChy`bMH&FPJYoap_c0WGa!rC2>==U_L^D|g9| z1{uN$W2{yfSP@GUtIWZ8FPeh;NZK^c1uZC0JNhdkxkC@?UUiV)w#S%;gLz@1>%#+J zxKY{Lh+|AZV$fHE!<(6{!YOEnI>G3L!%qScok{mrQI#|W7iI?)++b^Na(+bLEsq5y z_g?_~iZ&=Fd;|ltce<*rUsW`=aINbgdYfK0ljG0{k#R1(xpWkQ8!gw!ufklFF9k_u z`=@c}cj<*ar?A~;Zta_Uo#{jE7-~4I3CgO{2vBo*@|7Ig4;9*bIBAZA73vFyO}z4F zZr`+IFetW^05olhWUI~M`_RJ-$%w%U8|}txpL0vS5(GlThMF00EI^nApEKTf&gjJ( zeYAJVI4)@|z>|tnKbiU(kx^*0-$hQxqw|!~f1AjLoXD~$T(cNyhtNnZ0|+a;tkBn_ zgs$WZd#e1o#2^45t&rF8`6B$ttX%T8@c{0px^5wBGui{Xn;VMYdlnJs=ZXBa)j0|f zDId}@1P82$fwm`h)RDLB!KAio^Y{=u2Y7aX_nmVdt5Stou7Ppoe>h6NAz3nY{1;Yx zydb{VidZ8mG0F=t=bg`VueI+ntN5*d_t`ckM>Pg+&l~fN$6qU;^o_p%ZJ1Ugk!v%} z2Evh%dG0h?02I>PFqR@7ql43re>(^;0ka1D2sowFK)tu^ZIGh!srraV?%61C zh;fXt-<&Nro>0xBaT+2D1F0eIZdav~dUwy=k7|tdbGcffsHrGx@tvWi1q}LD+F4t` zth;0ucKu#xgpj|u7Mpst&?eo5bj8IZ=r+JG*MZ597BG1t4Y)qY0X(6jnzlE zY%40DHU!L2&$AfuqCMaaMHJyIuw;v0ZwvT@Bb~d=WaN$n=^C^{*Uj-h@T73Zg z%Yg-G-EFFnr00gLGq1ts!fWY%StP1#fh#23x_^y$)1l%qdZyKj3;{Ju^b~nRbq5jd zYG%*~N#M%e6QH7<^yAA`O~V@)3Y=YI5?2z1BDt0j$l(dE$dbca;~d#!pr8L^^oeS2 zgwYcAEiD?d!tB_nm6_>JKn9CDQ>L2o0VxFVGV2HW5^i z`IA3JCEz|H$ycP;5=ENVU@@BTWk+s{>R?>u{Yv4In6c~11jq5Afr|TgD|Ir}$HM9Y zCYm?Ev>Z=?Bm$9FgQ6g`+#WgmPe8?IpU;X3xObojhKukI{nu4!OVq+h*{nA$_Y^uq z77gxUiF6EarJRZf;tsSa=nv*%c*T@_&NOKblkHQs6=#4 zy+X2DU^KBoD%_!3I)nl1=4Tsdx-wh^-_6#`0SzlE7tuHV6R-gvTtxG!-ty{+XDpt{ zwiadx9$>l4f)o}M9V`L5IbEnh1(_4L>Sj3!t|M-K6cwT~WwXxT$_ob$B@v`q)m0^;q>U6$! zPv(Q%A&N5l!h8q|F=o?Qzyw)`oYG^@6Ew#HXW7j5zQe1F6s}+f?l9QB<(0lt@0A~HQ@v4%9 zu*3G0w&kJ#;cqje|L1#Ys^m8p_7M;>o(SicHXGq8# z=v2{exbXW=8OVEcWP`*9rJJlWn|?S)18j46HrGjeX?;w5>kQmIcr;WOnc^*~>x%a3 zOUXyy#gpSk|KmB#_Ec)BUm%aoZVdZ!TY$XydU})tqJWeSGWbe!<`cDc6h%tjOv|lZ z^A5AK@k1%3{UstT%J*d0XC^f7(Iq(JAHH3$X8mHZUS2Us_@D|Hqc~KPZH5}K9z)MY z0xh#jahNUsL%CylRp3;R0XGQiehfT>Fa;u53$czIc$>2kTL~xe930kqDkgM#`DwiD zs>((=hU9Yv z;=jm^9H1e)Ql3goIcQ#JYg2crliDA>ZBTNT2*uUJlVoM9CJjX>M&~*41(t&v!IxE1hocewL4+@w z^4bO7hqPU2HU=2vj5Cr>%zzrjeCN3?&tS3{(|1}dDG+j{Wk7oKt!=cGn_H;0;)d}k$_PNZMXX#sG1&X+xfulh@vs(L#4a~$HF|w6V9ufqsAs} zisyY4b_T2}0(Eu9kn6E3;7M@b~fYw2`AP%D1MUzBTExCgx{){3zKw zpDW}S$XWq0_`C6qM%ifb9ypQK7Yt{VOAPRspC+Va2;m7EmuH=3rw2_+L_AM4nRf>z zthN8jak=LVJVF>T!rOhyTmJTd2q|-sl;>P(O)}J+6&Ob+RG3!gN*99hZEgRRL}q6x z>=cQ2(35){#)uzFJ+cnWh+dLr@hDXAxI5l4B)wq5(ExQPkeGDC%XBN2W@m-kaFhKv zLu?Xc$5zCxj~0~fU8k?b%MCXOnE_k%x(F*e#%=<2A}@LMET$jE!#)IL&;zb@7%dN* zj{{IOf85Zl7n5H5^Gg-|OK8E+<0P#G&-17KptdF?*ed22u#iaP&#Yx; z?sg1h4Q`L>iV)J^dYy0n_6T$PRH$VZiD9ylP#g2`-@Xu?L&EwwV6Yd-CXSGDR4&-q zZAZ~6mK_FLkKjb;ITkHIX2`Gn2`kt5zU1NJ5+3UKWG!8wVN9eN1yTo1Nn7Dd3oXvF zi&dx#YaCuGR}7MrTt+z88{(w+{stBefbVNb$RD)LFj<0XVy*L%HJ!KS#!3Z5S{j1Q5bev^;!5cAP*RJK6JrHj>zota5^YQTHPvrT_qhLz@h`|mUq?Hg|EIMw^j zq3^%xW0$}Qe_dH2NjWx|;F{)foIPym-LD!hB3rm+m&9Lebx`k1c2qqJ!aowHtpWY# zo^Sq$wNTWjn*GIof~IxR0tBV1{v=1;bi;}#!;ghXLRxpTN;-u}^>`Rl|FPCwiL}Rz z0AOi^9DB1md&>SNRp?WV>#8Ov>1xK6+G8zZk3p~OWj=;?jXmW%m^T4b( zbD`@;cZGIj4A5}=m+;;&5{g1lE05V5oU`DE$_4OnbmtlAYCH#+Dk>*TkzOJJ0Nf`0 z`U?U;J-@T`U;K~#Q%9Kp$V74Z6$sa(5B++m$PWHeUxGD6^Nm^@wT>$Z3i1PTDliKNr=~Me% zD$R$?-e!TH09ocZ7A0)u(j5_QV1nF%$)2+&<#ZMKyg16xEk+Xbp2&T=eXm!8bLOlv z*Yq@Uop_;lFz;tI9D~u%-^Yz`ks6byF*5l#D4?km^E+(jgb$;So4ZHyE)AQ?-k1Wo-8#Cv3XQVyB)*@iZ%8M)wmfQi#KAFEoIKel`$g}zq| z(~mwMArhh|O=ld4Tfaw&n~h;QrQ66dHF^la&V`%Frbq~*5T}$R*q!v@u^0D*I#+Zs zVYS5~1jPO>QM?-~{`>tA69NqVDFJ1uSGm&fpjgDXCr;V|@@ROcmJO}oXTaB+o{zb# z0LU<~tk-OPpIJ?01?(puAgX0!S;q>Ebyp;0=@bo1eXReGj4ntX?bADOUI!E+-&a99 zJBreUM+9`|hALISj?u5&I|19M9)G5ADt@oK@nc(;fH=Tsw)J7Key3;{@s+xiiy8)Z z?>Rj!gifz`8@+OD1+M#~)VlLHf1{(S1{6Huvd|u$hJm_|2hg+daao|!X0c6->Jmz4rigC# zhFNi&iscormX}PfeC-w&IejL2QZDMdmx9^CdkABD`T^yKNK{CwYmUWGizg{;)z$-g zAwVtIt>MihVD`8sAWHv=PSvKJN+K-Xdz#@I)A!HUJZ5^0wriHrv7>W`5suO*=SWA- zhbSd4Q(KRy0d9qL$H86S^hWiJHyN2)&c}6%e7QBh^T7ghTvQ2pP2HwuV;0s6DCmTt zi_0U1gV2SRDDO!2Gi;I*#hr80_$u;AqiGk*pifpX<(4J5r}ufUb)v_ zzcz6h&8|%!XuDs>n?kMz?()3iUisZZj_av?DGj#|JoI=kt!3kGw~a*viC*;d@d4d9 z1PDSZFV+`PsQ`f^biZ0=7=ZgXb3`ZfQX;JKpY+@b))xHHV~INagV}*vzcWj}@7aQX zHab{k)H2CMzh^o78uzGzHt4V72bfy)lb^x7oZ=uDRm58Ig&;bw4!uj|3N2Nu>_$J( zJ1-am1p9waRQLSqmaC&nw~HSx)tGwF3$=H*YXhAC+GEKtb4fbJ`1nai(UD_Bm4D7$I3WK|f(WdCA9YyHHHhBAPR)>-eQo{!~9Ofx236r9Nk4Jf#T zr!6Z+7TZQXC*_`*9V*^Lpwxaa6_&O%^b#~HS||j?9;@d33FI&dw802+njNBTpAO+r zN7F)}Uzm;Kqy%IECPAzQc!$K#2cq7RpmDNCsg5+tPZRL`);uUNoVH9*17HF(wE(~Y ze@%EX1!vAT4j-ne;iT+BpjUJuV+4JW?DNT>Cw_e_+_|dVTGMT!YIzN`_!m3$NEK$3 zJDuagV`Q4#xr*n{|MmJqS&*xg8U52E{f;ae#>#2fMb5I*t16uJAwWTMwR-M4>sQzP zDse_=&@7a)vLc2{@^>>F+(SU|>!*|RaX5@-J6^ky-U>$EYtlTU@WEfUgcUya8Y8b< z(_nS?tpD^}ZMs@DOz$JzQ4cs3csHLgM)F9<@=KTR-(4-xWCwJ|KFLg)Z&Ql4WPu;` zh)htgj#&jZvFnirw!Om>nlSb(WkUvsk8S_A@qw7fYSMp+uK3R9=I1fMG$o zOjVo~@JmfLg6zs#<6VN*rZTPRt9is5eEKI%FU<$60cKeV5~G+jznJW5b;5wWaHEoC z%B#?~(HDeu&8KZc>APJa@G3H4-b&6jR~r^Gir2xi1eqa-F4F}rQzbWfSnvEUY8A<< z*GH|v5?;ei@?8UGez<{nhS~>}Jf1uqXZcd1P*T`hhv&7YioukI7Gzv?`Uq9ch2a!v zNpacI5IMTo)QrihL_@K}Z^hFNg1_Q~llbI7G;*VG7}jdRLJ<6@`P-u>ra>T9%lfL+ z*b{>in|WPTrLUve-9vRJ|ALU;X%O$qy;Ow|6azryYvwwWoSfn3YJlAGGc?lK1i&>| zf*pPG_~zp+)XN{?t#ZK~K!G*nvhLlp!+k0+T;-5OU~ZltVAuJ#z9RAmPBXRG@kx7mi8!$)SL=yb zz+(}sn5M)Y$e(p01^8e=`egI_$K((t!^w2!wfZ*%#N}qj-=OT>`eoj_rIQ(}ru|F^ zmh+c7bsdBhp{2k@F;gmOrM1o^P#g^Q zGsVi6JM>xiT?z$D-KW?Io6z(XtHh!{Lq_Mnw@5m$P(9g-xb$*_R@xyLe%(jD)AH!d zfJp~u*JEudQ+Nt1f|PCX^wmMm=ZN7D6e#}s^RU$zVTdc%MsI{<#rc6|Qru=w+xJjr z-`H|C)shb2Oyr8eylKnrSSD0@|I{FB=m-gAx*Q8bbtN?fS?}WIOYnZr-%yb6 zSp_{U%!shqdzU3+8pan6BjloFkx<)?_CFs%EPI|zwT!o3ZBpptDzU>r!?A0n`{(>OFz3cKV-A`l+3m=**K9Eks!3+dGmw5| zlWE&eXhW(j?i%;@KImc0Z?0o=FxaEECj>aOwD*LS@wPUjE_3&(O`UM7+q0F=9bjyt zr`S!o5nwH-A5~fwr3~B~z~dsv6aArN!n*OQ!NCfskILFT%VMCS3&Vr#X+!w}Ww=7R z%p@$;qTv!RnorPC_HY>p)kVG<3<@0xcBT%PGb^=azG{NM|)Gz;X z&tU62jE}&{|J3cwbSPb6TkvQ@L0Thms3+6pM%KHus0_NO#(4sEvPHW4a@?PEW2~IN z=2}Y$36^$=Rdwaa+}S-s58+-cYlt%W#VG;$sV-)1eiuH0?sLJ>WwsQ$+)rTDP>K{%8Sl=@?&xP? zoEK08EYBCiqdg=@zanOmgM^BDBjSk(M-0Yf7J)rqR-2xNXaN};<~Tr!a5bx^rLp0`)k;Sq3B5#Hj@>%ELIMh0^3bp(3y zWwIyalf=Y4FtF(d%?qv`^494;g{K99YTqItg}-{_KBOLbzPmf|bc|Z!d9GQPV?LYj zBIk~|jfH}=GtF`|eRh6hRxF}cK_TV}9T9JkLkS^z=3vw;B`4E(g|+C$x1mIXPFBF+ ze63a0ekR*}$@1kZYGtD6;CRC}nq466(_%KIezC`eI2_z`{fk>>ikl@-i1bIG`vi0Z zGW?jSKEGVO+Ov1-#Xs`-8QhH=3k5`U1}~o|?Jfn$Tuy#JeN(w<#Xq^)}wpBM$*xYa_3jb-ECYB^R>W8^=KLdVH3M;7(W5>pKrQ{Gl zj71CVKTc6*)rNxykj@i9S5C!r>!C5T->irGM8?$&TYAwOJ*IVHzxW2yY$gvW#$%<@ zo?1b7`$c4u-5;=(q=Y!N;Tq6;XVLr}6M&4u$`W5jttpE?9j0i~ACm;8O!Kc$YJ;S;l!bOxF3E|}0G4tJ zh{28*PaUn2Sag9Z=khJ(3QJVDt!!$VPj3MBx3=PjlI*r>*BaMrlyk z4!P(~v+JH0hm>vT3OO|KK5lVK+Sw@HFj6*0zMfIHTp);wXlr?5L_keU0qZFs98?|$ z=iYd73t0IhQ-{v$GIxE16g^}Mu|WrbQQHCdAzB_WeIhs95OOd1udJvLitNnus~{1f ztoQG~ur;EexRoi2q?+@jLq{zfsye6z(NMsst`{Nm6}To(qCr8j_cMU3vP=OqWiy3E)#C*g^sOQL>1V3_w^fygG$r-_cf8}LRXU(1KboY zH?#mAP*0N(h+j&P+ ziA%_fuh!_?6Xp5K6Dv+2MPr3fVqM<+SePCJrJUZuMxQCTVe%T=IQc1cqF*$ge=@8n zaSqyqmt~EQGm)3PBujA4k=V08gMbd!nk&#<$Ogvk9qZiA|K=pqEKH|hyX%oYna=7L zHEqKw+n1cgc-b=hXi*rJMJdsKe0-&a6JSNEX#c}UjlshmLJ8DwXUuY6mXMI@FN*8p zTmDh!nNzJz69SBw0a#vJwH~3yhhzAe!-#|Xpx0;3f+;1$MtS1`em7PdL*qzXse^4C zL-?DA$tAWpHxSgdnr*C50!6M~rh%p$ZgqqxC%-;~ZOjmOGA{aaqp#K()S%;h ztcGH_vwW`kaAWD*BPHWTG69*1O){1}rw_pvP^Dj|M~d}2+Q7&_&0K)47Y}Bo>s=ni z2fbuVpjdzueJmg1CJe$`zNlf^&ivQ}f@BRc-GdO_2w^wbY4rV!Uwogg5U@l2N6GFI zNS62<57jW{3nutZox<4~P+oc3t3UWA#MsP|j=*x~z39V1|}! z^VShN<%s}?ZiSm6QEFB^iR;FeuB4Q^8geaLaR%xRv1+ChI|?O6;p2+jV#qKz?Yw+o z4{%wl22T;RA-6cIQmG)HQX0GrlNBJD1E#j4br)|F_@VCL3@F<63uQ_dx}OhB=WHu` z_I;GunRM5@`a4h-e`XLc(C`?4{+REG1Q=u=Xj0=rB}Q2c4lSaE&K<_ttnFOsFU)OY zxCJJ(QWEw=JrmZ?rI(B|ZG>IrbOCqyUvM+EK`ULpzcfn@`JK!IPn*_buP9!O5k-%i zmgh%9rPL}0vleX+&@3PHuR7+$V5dNW@ardCmF8H7qQ(fX-dn|QOR{h7>-Ia91+nPMNzN9uAV7beaRC(`3c z60RX@rrD26L)(=Y-)66{x`QK3^5ddPHntKY2sgOUEH*E22IkE1!fVcoSxr>D z$%J!Ll3DR}rfL)PG}!=tKS&bcr~#c`XHoKZRdsYmYrXI3zuiW1954xi0dwyg zRNbC3*Z$o$|F`m^(N3yL>;LJtMC7LxAOO$#2>kz~+Xf7w>i?T=yUj2cCiKA`^OfrQ zE3$?D@Dwi$`@Tst8m62d@nr9vZHVwl))zh}KDup`aD3e?SJezH3pr7gBs8TImwz85lALfQ9w9U~G2ZD3L@ckBjU{eMlQD2B2xQ=NB?RB& ze^ZE2>0)zP2l)Ie^XfF_7vloR@dK+5-mE|!8GlwJ_2a5f5~>U1keBX9midZI)mCUG z%K2W-8h9A48&sEk=2)H=tunQ0A5kd~%wD0lL=s>1Q?Sx7`D_uDXKSrGzxGtDBCW)p z{gjB1q~h|a`groyF{CX?L~sw-Zv%sFZw|{a>ar4tRNt*z|6_*q65o9cQ66(4*&J#| zMg-P&1`i)5V$}uPz(BIh8C2)Diq%Mc9@>kCQ7}EQ!bJ^Lk->=2cC#dqD1A|CHLwz8*K`%js z7<7pMvoK7m6$eV%_7zufPc2gaj~Bb~g)!&P!3k~F?Xk)OM2O;+10ZY3(aXBD-yh2U zMFEb@-UwU3Rt7O42M+cQ`rfqEsQj|ZP|F}Go$c+QB`VR!xSqi-E|~;V#a8&Nbp}{M z1#yG&jLlpt%scHip4>p@PGWJpO}sn%$q|uf81%81bq6{bh4s+=!_XgPs>t82_w~ET zA>x&|Af}S^cfxMe6jqli?T(!jM>*4rHc@Pi(BU3%WhApfm;#|DPwa*M<^WY+eOzqb z51O%s4#N7$;ei-?-Ht|e+!6!h9Pj-Ral=v5r?JpdI!H#F zbKgJVChGiXgffjHEf*EpQw9UKr+%Ksk;1N}>~&5|Dwfts<>vDIDM9A-Ug@|-gPo;R zUU!Fp1evX2Y~bZ?;x_C0tMJ*VPJK(B>=SHd3!~jkFxtsL38x(GAXMIK=9+c~rJG2U zcSt*_5?Kz^Yc8}+^ag$hY?FA*h=9qOm4Lu8q3bMtdEL}r-4QZ9oB>{LLd^ z?gLHOHu2Rh1m#MWYI^;NY%fGIAs{*C8??1msON323tNtLhPj7A{w#BkP0dj!9Jck^ zJ|_-mn*A ztlMQH$7DZT*}H41Xj-WNGn<+Dc3U!BQ%d^9Y`eTLW0gM-*#x^AEUvmEZ)>GwYQvJ$ z`8rnrZZufYB2uw;oQNX?W+DJ&sB2`AG=mSV?-mzaylHq=S->k(USUKx&7Dd*8(1Dh z7iq9U754s@hfe5K+P`jck6q$BY7G(m=5KqgR>GvHlCCzyizBFNfKjH-vUeFdxn>Bz zX(7X4C`>4D;gO=f+1;xNza>h*?Ml#+=6h}Z1kTBdEbNJFPA?8ss6*DT!+yDc`MSr? z&s)<<@PK8tq`A?BRsDcRORK#OWI&wMM=5Ni?1#mDj z225NcK$=M?h>0+hPWsPYBT8;t^s%3`cSn(zg&Gs^D)X^}#4A7+2B{3GUb6hVYL9~m zH#h!0&5XzNETjFjC>A4Jcvdapa80|HUclPSy@MG5>VfGP4vta30^ZV>$f5C*f zi9_qrKkNSG@Jmjb>W9P3_v?BvVnI0MdH8i> zrCC5rXImw{O%?`qd@W2Lw~bNj=nmXH(*+X14ijQhla~()NhL%v=d$7lvdW#rf$9UY zizPjSI_P}9O8Urp+c&h5*~y$Zv@uswO2#^5!cS$N*yq z8jP%E`wzzJ-~j_fMBjz=>N1Vn3Wdl^(&_;928xdZ%Jvt`U+6RaSpc>3pZcAxK{i=_ zpI1QkN7@&O9OJ1w0};PO`8ncn=sH&{|F8~l4BTKy|P#5Y1)Ua!@{M?wPq8*x;!)4BAO?Pd~WVJ)VI_dnW>a; z^Qps+h&+6{*IAymjqVIWWjcJ0yDJ@szySR}3b<%)sKERpVx-$3&u zNPsgGgIBqKXZDhJ)qP{Rl{u0hNI+5w^nW|gWZu1A--5ndAAHF$PGI*Oyh`&)D(%Rv z>N4^S>OO}+PBlZlT-2Md+q6t?_gH?LLqU#UEbQinq|E%G+HG-)YE)+}mrt@bSUdd| zR2FTK38g0PbA{9RIM-%|rp7fz1uTwh>K9>qj=>9;@|9-Q>(R}ycs(8H<-2R7b5&?N zYPCQT)l~{^F|!v91MtViO?%5oR=d6MwafYIzKDnP_UV2nZ{y>23Q)mSi09U2C{-W2 z;2ME7#BG+bF+0dx?_PTF*hU?kZvF(KmJ;kv|7xqQw$l7T?D#Ko^B^kRqNtPE zv9{wldLrDbC(E}s1SK+#)z|qBT1ivfH^gC$G=OnGKD6=%_Su+b}qqO^e+88PgEKAD~s^;IU-W zp$Xo=e7;-*@PbV}0z$w(j zAYgz|_Jq>^qIVC%?hrEnAH93e{*q|grwS(*l@x{a4m3r$|AdT-j9nLMu?9Cww3_Z` zgbY>-P+{T-fm9B=2h&aK<6jlZ@drsuyWOb z3pCfzhnZ>V#HRvj_&Co~_6!8}$VuRcHD%-{fp1>~l7PFVsvV8Rn{GmGm<6H0MGd5B zUd}#H)p7amtSIJvFf&*NZeIFZOzTHVQjC_3xxMMi1NWr*=%n5O6t>l%Bf3JuiVj8Y z{+xuLQmt zPWl^2#j=N}A#IS&&5At#WZxLeG^?41T;Cs1ihyI0_e|R9K;JYAL2q|878mpDhrIMU zoshaBvRZUy;lNS94|4#G z@rqHme@Xy#^6h^0IqS)6`^jLx?A;T)Ba`{od0+S9Ix+FY)QPYjEE_2r%@q;-S>|;X z#G{;O!&ISCt9dsfwZc>Z5Q|ELQ!%GY4nQyGi{9GnH6qDXAw9b(PhMBF2d3BCFBcBU za6HPker;MN!qW+infn~L-q0P3n@D8FzjnhcJw9LDj}a{PVXdg7C($$}!6Lgq(1649 z?rx8$v^jEmxjK}_KI8KNXEzWSiED?2V`&Xh1}Sj(mM*>B&UZ0a#;I3_`h1C7=O&EF zg*?X=p&kpa#8RcR7eyDJ7WS5(L|m06GW`>4l)5J-QGJVL{N-3~7U&ivnNJbs2ao^e zzVqQy2y_rZ@ibyxL0jK8`L1zHx!P+dvK?5*^FpYBRBWm)d!ca}4aeu22XMrSw=X9t z_U>^n+KyZGk6v$n7;Pj+g8&+XR6Ls2_bXo;nMii|`Mw524}0|m;dXXp%)4e&5-^!o^jb59h0=~j+6ti?h8%h(x$yKaC?=OSsaqQaMTCsT7^-11k4hn)e zCa+24HeWV=cBRY>7+{~{pj+Sc)OVx8QJH+WBeIx|7HBu3H!5DW#BVf1fbqPPMtU{p z8XSX?kN_i#)$}E|M=#ifUATI1Pw?VCuACFQgw#D%4;t5Tm86HcblN zE<(*AOJFKy+IvwhDS>_z)Hr*uwvub{`v78FbO$9EEkRwMvxBAk7s_jDlWh~MYy^MW zJM(7le?n2Fcf;^`we-SK=#T(IUj23yPODDl3@pKYzM?KyRn=-SzzK0Xh26a=3VRcs zqi=iTu7?PdVd+c>OMU*~bWcS?Lh@VAL%pZB6E-J*@Yu^&n`MwhgBJFG+=h$rd_;;y z95$N}f)KFZeIt;~8b-C4A^po(S39-2nS%Y&G?kVusho1oyOq5Z?OL(??R?P$3C`O@clJzx%hs~KNx1bg`>s~P)6tESoJvQ zfEv{~yXx=g2%X22xJNyiG_zDq1w(sl{wcFggGw5ymU(*msqYO9vfAP))vb6di*dgs zptqaVSpF4uAW4I`Y4^X;cR{pU1Xf~wENed=v`2u`Ki>2xUA6=}TJ!t^ZDaPZEp*Hm z?Ji`XAR5y1^o$~J?lD{W%ip|=+GE$ZA1LsP;NlOIQ&sF1b}`F2a2>yoHSqT_NJD&U zGzj>P*X!PiK#kWao=-f=Rt5absn6LY?LAO}fOTD|NPl%0lezuIA(7X-sUfXVDOb~p zCucVn;x5OPt=e^qOCHdK*$`X8J^>#Z9%P2U5@Btns+26JBB)9HwwIj4jsSR}fEeMa z;rvjXBIwyO?wltTxV64)olN_+NX$>UJ*IrsC&B`2XO9)=4BR9%+J}6^>V4;{1CHP!g#7OMg;Fv?*R>nix>gi3-TXQH{|Fggzf*)9N_cw{Lt`U8K#tSo&0D&s#02chUmzVa8XD!!$w0S(L0#Mg5o$B6=3 zPQYQeu)X!^MZ4;K@o_WEptq6yk8>s}cMt=xJc-#)!L84xjvQ>-&62txbg<5j`3}Zp0YhWE z;d~vdnw@J}6^%ge*=@0F#zz2fDy2PhQKei>C31g!!%ai`=U!l~jcia`@)%p5KTP0XzS3hEL1PG%;v!d6b8(blYz9O3N2@WiZ8N%_yKf}n&M9}W+=om zHHg1#Qm$AuhQic0u@UR6i){f)$>9k8Hj^JihM9Y|i9?(cc=9XWkl;;!Q{ku4X})I{I5UF3(n}Wg;4|QvV~9 zcjcZe`-VYE-+y83WdcD2({P-fjVXIAZI`Unt9p1BzBb~1PkH?&Zaan*4HbkE8Kq&C zXSEh5-70&a(4Abj#?ty#)P>&nDR)?7q+M~)#gXThJuq@o0YcCY1k;dJLp4uy?>CN`GPS?J)>VV!jR37&7vFo zfSy44iMe4%p=la;v&MPaptk+1l)Ch+Kvl`1xNw+wuj_l3q*X{`$ee4<=&vd{6>kZO zM=uZh5$aobyjF^c#dlbB{C%;^EH4UJUdwY$&XO~Uk!2cb((Bm$@f340sP}AiQ}amK z;$vX7jggrZPR@y!^G`GAExUITcq`xi?wgXiFe=U#gmG#Qeqd|6OFFMEO`(8W#h;ED zp8MvF+x%%IHHA(yKOieWXS_*J>!(uEf0CLVT}q2-5Ca%E6I={3?oN=jN<2cmAT;F5 zdR)E*?thJ)Wmgp77KMlIhCvXJlo+~^MjE6$C8Uw=mW}~wkd~SehDI9ch9RV+JEcn) z;Cesa4|gqp!`W+}_dVyVXM3e*%n_~GT`rBw_{G|!>(xt_%|uKw*$E`v*hm(0ll=Hy znH}_+!?I>32l0Jbanv~fEhLgV-djqgY?NZdG>#VAe>Ke!K6_yHNVP0`N7LnAW<3p{ zZHL~gB)VU0k9Pa0VB$;Vn4d73D{RJOF*wIuaJ7{4HG{^?9s;&-tBp14THAS*MYK-J zG>)5l$e)3{vys`0uJPs-ae@_3m0cwB8F+Kze^TAY)x2ci>Tf&+6^Zi9SU71o@umEQ zswaYKl;U-jtbKm^5PQBL?bBZ?8vOk*NgL~?(}*d!t?9&LS^p<=6(4oiwB4;)G{pwm zLp?b+prb8nfVonoeaEHs#?x0sG|(*4*jYR=vyIJG<5oHMO?bpb)p|TGoi^Sb*~D`| z@>6BWi&!bj&o08a&)P7JSw)?XAmZ4sW)z0*%XIX3%JkD8UUoo;ENTEvilN%UTJ1V* zhP{=gjwys6(8+4TBL)N}?#N%OX0{8ym_O0Yz?(`h=(@mD)Qu>W-AJ+-xaNKD^B`Hu; ztYo>4W(%H78c#QAW;pI<03BGxEv=yII<}h z&5N_e>)Pv(g&4J8!(95VLqhQ&e@_J*OzId>f` zWoAapOT`8ojiB)AU2-DMTwdOEFXzhA(}OF^yq;d=fmdnT_Ac-r-d0&gK3$yQOebqr z_}?rS0R`Mi;+ok%kHDIhi=7q#IoU}QB4~nz`+44M5kuu!M7`_}XLi;@ z$>$dcehfQU+BzhJv_E9WV;R55-$b!&a96PWse^ z2qB$O{-&!c4DdY|lMeULsf;oT_2bD5wxeG#em@&XbtXKPWoy>+_TiXD2FiSb>M6J3 z0HmUC1|f^0xMqK=oBP6qke|j>-LIbTyk|=}Kjb#=V1+}GMFavf7hfYFe{LoutN**p zOJG+Rj72Ia2Ou@loq^E-ruOuz|1#TH$09aYxa)IQ+=+Xt0$eHu&RH@}V;jk>mD+sK8yHogVvtUd&W$H=Z zXUHI6lPvlzE_eQ8F4RaV+L9(c5|j>#HKzZTBKKkxRLP%k$q{|>rqJDraYubGR(o8; zSBkqAi6pL4RX1+W)*c^216(lm%+Q~LO^R08xWu>LusZ#Y=Y*m0rW9S-pbd?YSID9)G@tc{Sx*|73>tw!u zmne5ZkXgF)MM;cM8!ITbxRh32CoBye9DI66+CDo0!m>~3UM*Fb=XRZP8NEv&7SCFY zlEAP3o~BnlHFSi;D90})XL}u5^TGBcJje<}bFyoLNbubIuH9Ac#1gP(#hL>)ga`e6 zmL?`kFrpN0-)+?ZgaxkK?dC2wSnjdLX8s;7DYdO&h3wN6OA--5E63PRL4@deDGto$ zjOd)GuE4>`GdoyydeN9QfuO~*V?kPRX)y7%fSKg=zF%yl|2jZHit?9FAQlw>=?b-+ z8~`xxKymvgU1ETcT>ed$)9QyVCB;HCCv9GB;h$Qr4}O9u`hQ_euScVrc9=7iDuv4YlnKopx>Iz!{MBdko}R>l zUTWk_V71ihjpM}`&v#z4Q0u41GE%GJc*e^IUkug9JzW@MTf1Iv-{p<|!2Nr{N2qAX z#(QaUaV7|X0j&;K79{1zJN#0T6RW;=PW=edcsWv5G2ZL^2SterIsIeJBPPjbjE!<+ zkvtb;f^U?P1me{AL-bl+w4b?7g%c+h>+b})tVOp+ZX@l z!zl$bp?9Pum0$_D0g}=1^JfvLhrjt%-U_t15UFzS_x#qv`x?9Rd@eomTg*8PZJ^dL zWSaLXD^8Z2Oc9sNP>4g;HRcppiQHjL`+e8rmK<3~Ws2dl5dcvCnm9nLr@{h2ibtu$ z2LOt?iyr@}Uidc1eE(Ljr>c_t5zKcXwRd9m?%=b{UTQ@y6ZWOfZ;Hnf((hXaL$b%& z^C)Z-5@C6bf=OcEH3K0(Ol$-X9`MI-EI-Uki0uf*ETXs zW%Stp5QpKqH$aV7gX_RSC^!^MDe+8|p0k5aImU!E~66^zWvN8CD>pjl0 z2ure=-5yrrJ>xX7hMFKj(39;>pLJzp&XL1sRwMA^n>JB)uYu7IZm;62f|^B*qWa&( zb&d?f6DSHALZpDy%O>A%eXVMEZ9H2LV=)^SN9X(%PO)~8h{U$8K8)(E9I>xbRxp~{{Z*0@l zMNBOLj!3W#6JLFOx4z1P>eQZGUjO*6x@1nenMq5EJ7XG_$OelQJ$?_D@`(S08Pd@3 z)@e#Uu46D$Xl^>7Xr)xF5q13BA^H8^-sR`EF=Wn+y$L{qqwY}w00)oH|CFh>&P0I* z{Wr~>R1}+8@ze)a!&@ZTmzhMFWYZNwlt{Vh8S_;b1q}<^yvK<`w{V5)yG6~^0ikbR zWprA=rG}L$&6yX1Bg4prjL18l^mctc{b5rmOUe9kf)+7Zpb4SIL9<$#cu6P=X?6d{ zK}t2%`POCmiDi+=Wh<)&b6;@{N466@A}MxOG|_0)if~{uB$_fC{=%CuW9*WA_%)Wz zf;Z8$+wq*Eh%40Zd*4^h)v*_TY2C5k2Bi0q-xr7lU2%hFFRU1f+@f9 zHf9GZrYS(ur^OU+A$@au4Bd`1LH6?3KKlddpTvSy3a6PnSLK!mM1GapjmL$pWsu8#eKr?$wm^@O889n^k~PM|`Diw-Nr3sKMXn z0}BHs-(WD7`FS^@B%CCxG&J=EEwa_rt>jV*+|zG`8Hw#TkhH$T_bTf1Dqq(OM^g4q z#t!Iq#%$!#0c&#n9X#SUTtCYZ5e4p{ao=C*|*7&6(-&vJ_!x zt;gA#tA6g)3dAVL;N+k>u%SYxMb=c0(=e@1l~8^975CG5*qAHWL`OrSi@?4^=2Ld? z%u+K#sNlV*7`|?M^c#I)VOEMYJ>NukQJq#Fiz|*ioraqOZ<1#WLrQS9esi6s+D_l0 zmgkEy=oJH&*p`Uk|V)kN?hE(FqILPt`$9F^6p?yR-b|Ex(jO3|- zQ(WA==F&+1i9;CkvuC4DTjP4$l|^7%hQs5+Bn+{jk-w~M?U)b5K?%c&uZLd`IUC@9 zj4$B$y;1cm9SzmOPo$()o-3NW?IC0*4mW%g^;}eh;#0ZMGc0bWU^8olV*6I=E6bgg zm}?LZ5~L%9Fgt%3LY_;PQ^VH;)y<@5W%!;%fF^TL`kK5mtr~4O&EJM7fvcA6B^xFd z{BZ|K@yFm;-(Ff#5s-%GI5a$mTm{|iYK1jVZBPQ3Pxd#-X5C}tNc%I*m_JRwsuR9u zlgw|gk4%pU&L9i4;7Uu1eLL=~EJQaZQUe)X<4w$a`B6;$gQDrNO4i(^Rp1n)=MZ#&6Tnf77@(imJQR-_LntFQWeREX2Uei>}> z1uE_)R8!l|#L`0G_=ryTs3MhaYs8PXK+x={dtL371^#{oxo^T({+3P7-Xya;+2Xw5-GxfBmk`^{VhSDPgp%36uEyg zLxU?eUHAB6;l`aI=UT!4Z3@I;OK393ux{){Cbe9b7|-~w!+7`b1{u%3Vd|x$FNOsH z>u%kIUA?O7#$@+)b6jO7PjIc2W|f%71pLYUK`ucd>VQRi<~nO%ts`p=bZvWka#Iuq zWEHSxwHI)bi=FnP{p<7q07a%nx5Q{ho`rL9# zP`^FDd#(1chs}LQ>=(c;y?B23;jm5k4yn5*p7@yjaE5pZ9R3s+d+#`_X?m2eRj~S| z=~mCA-(yF01D%oj*T6dpylW8VKJB;7ZMOwO67| zQMuaVI9JWM`VejJR(!i#`Oca%NjbhPtORQ&{+Ja=%s@R@(x_N+cHC@lrfn9|=QAsP z25mpE;96wmBJjJUEHhX+%QUkVYO4VD(xiS~e_}|L^C7prmBWfPMjz6hvGiNdJ`u#G z_y6MzZ@Nsi(`)=hCx1|zQ2*+-4$p4bgdFn40LU=;K4QAiIOd$bZ(%OZ@ z!W}yUghli$BPcOM!Mwj`VR2G=P?aq}Lqj7mSn-Dvn|zQQ`D_tZ@q>A=sc2zhR?+@Q z7P3c+PW&`ohcQB3GqyXC0^5VHJ4XxH!hPn%K&F0UfB`PIbuiy-t@X=%O9iGrY2qu3 zWhX$<`T6@3QBPt~%utsUC|+5u zsD^Oq_v#C{YNrOA7gptQ1YCD|$pT5=a*M-`MH^ujQ%X;*{9cb^K?i*JY!@kOa4t6C zr~D61Jv1N2Eo0a)lIvN@lk36v@e!vy8hfkmPI1x;8TEpZrA;$^B3Q=Uu5s;zp&zSF zw<8%R@u-M2T7?((OQ~-;58LFn9OtQ{9fB!SGSrJQ=9Lr148V3S5H`dKR z^n8)giT~+x@U)6>vXQhp04d3tj##Y{t!=nivXV(RQ-+HM&ra|nRTtl8tk)$I?~Jki zOn;`w0JbdGy+JuE?4c>Gy?bCKCMrt5C!*DS_M$sIs;>DOw>r~AnLl8d{itRMMoK@i zwmq~aw0vN%n>5{LXi$Fe!-)P;V7lDI0f{o2W0ds9xk`Aqm2oVIV6&$mrM;NCOoNHA z$@Qy>8rID73MPmy4Mpul0WKi4A7>gnk!NJWsMOgp1!b;PoX1F?V-1BJK#g@IX$-WH zKSyi~e|aRh+oeE~SMXO!82fyn-p9iDLe=ZFTig7+^AizC_3l1vQ9e=xTfBd%N%35Q vVp)2Rdi9gH782HI`hv7SL;vfI8c!e9WIc!v07%zZt-=7nBqQv97$pAz_`bB? literal 0 HcmV?d00001 diff --git a/tests/testflows/datetime64_extended_range/tests/common.py b/tests/testflows/datetime64_extended_range/tests/common.py new file mode 100644 index 00000000000..016599ce34e --- /dev/null +++ b/tests/testflows/datetime64_extended_range/tests/common.py @@ -0,0 +1,179 @@ +import pytz +import datetime + +from testflows.core import * +from testflows.asserts import error +from contextlib import contextmanager +from datetime64_extended_range.common import * + + +def in_normal_range(dt: datetime.datetime): + """Check if DateTime is in normal range + """ + return dt <= datetime.datetime(2105, 12, 31, 23, 59, 59, 999999) and dt >= datetime.datetime(1970, 1, 1, 0, 0, 0) + + +def years_range(stress=False, padding=(0, 0)): + """Returns a set of year values used for testing. + """ + return range(1698+padding[0], 2378-padding[1]) if stress else (1800, 2000, 2200) + + +def timezones_range(stress=False): + """Returns a set of timezone values used for testing. + """ + if stress: + return pytz.all_timezones + else: + return ['UTC', 'Asia/Novosibirsk', 'America/Denver'] + + +@contextmanager +def create_table(timezone, node): + try: + node.query(f"CREATE TABLE dt(timestamp DateTime64(3, {timezone})) Engine = TinyLog") + yield + finally: + node.query("DROP TABLE dt") + + +@TestOutline +def insert_check_datetime(self, datetime, expected, precision=0, timezone="UTC"): + """Check how a particular datetime value works with different + functions that accept DateTime64 data type. + + :param datetime: datetime string + :param expected: expected result + :param precision: time precision, default: 0 + :param timezone: timezone, default: UTC + """ + with create_table(timezone, self.context.node): + with When("I use toDateTime64"): + r = self.context.node.query(f"SELECT toDateTime64('{datetime}', {precision}, '{timezone}')") + + with Then(f"I expect {expected}"): + assert r.output == expected, error() + + +def datetime_generator(year, microseconds=False): + """Helper generator + """ + date = datetime.datetime(year, 1, 1, 0, 0, 0) + if microseconds: + date = datetime.datetime(year, 1, 1, 0, 0, 0, 123000) + while not (date.month == 12 and date.day == 31): + yield date + date = date + datetime.timedelta(days=1, hours=1, minutes=1, seconds=1) + + +def select_dates_in_year(year, stress=False, microseconds=False): + """Returns various datetimes in a year that are to be checked + """ + if not stress: + dates = [datetime.datetime(year, 1, 1, 0, 0, 0), datetime.datetime(year, 12, 31, 23, 59, 59)] + if microseconds: + dates = [datetime.datetime(year, 1, 1, 0, 0, 0, 123000), datetime.datetime(year, 12, 31, 23, 59, 59, 123000)] + if year % 4 == 0 and (year % 100 != 0 or year % 400 == 0): + dates.append(datetime.datetime(year, 2, 29, 11, 11, 11, 123000)) + return dates + else: + return datetime_generator(year) + + +@TestOutline +def select_check_datetime(self, datetime, expected, precision=0, timezone="UTC"): + """Check how a particular datetime value works with different + functions that accept DateTime64 data type. + + :param datetime: datetime string + :param expected: expected result + :param precision: time precision, default: 0 + :param timezone: timezone, default: UTC + """ + with When("I use toDateTime64"): + r = self.context.node.query(f"SELECT toDateTime64('{datetime}', {precision}, '{timezone}')") + + with Then(f"I expect {expected}"): + assert r.output == expected, error() + + +@TestStep(When) +def exec_query(self, request, expected=None, exitcode=None): + """Execute a query and check expected result. + :param request: query string + :param expected: result string + :param exitcode: exitcode + """ + r = self.context.node.query(request) + + if expected is not None: + with Then(f"output should match the expected", description=f"{expected}"): + assert r.output == expected, error() + + elif exitcode is not None: + with Then(f"output exitcode should match expected", description=f"{exitcode}"): + assert r.exitcode == exitcode, error() + + +@TestOutline +def walk_datetime_in_incrementing_steps(self, date, hrs_range=(0, 24), step=1, timezone="UTC", precision=0): + """Sweep time starting from some start date. The time is incremented + in steps specified by the `step` parameter + (default: 1 min). + + :param hrs_range: range in hours + :param step: step in minutes + """ + + stress = self.context.stress + + tasks = [] + pool = Pool(4) + secs = f"00{'.' * (precision > 0)}{'0' * precision}" + + try: + with When(f"I loop through datetime range {hrs_range} starting from {date} in {step}min increments"): + for hrs in range(*hrs_range) if stress else (hrs_range[0], hrs_range[1]-1): + for mins in range(0, 60, step) if stress else (0, 59): + datetime = f"{date} {str(hrs).zfill(2)}:{str(mins).zfill(2)}:{secs}" + expected = datetime + + with When(f"time is {datetime}"): + run_scenario(pool, tasks, Test(name=f"{hrs}:{mins}:{secs}", test=select_check_datetime), + kwargs=dict(datetime=datetime, precision=precision, timezone=timezone, + expected=expected)) + finally: + join(tasks) + + +@TestOutline +def walk_datetime_in_decrementing_steps(self, date, hrs_range=(23, 0), step=1, timezone="UTC", precision=0): + """Sweep time starting from some start date. The time is decremented + in steps specified by the `step` parameter + (default: 1 min). + + :param date: string + :param hrs_range: range in hours + :param step: step in minutes + :param timezone: String + """ + + stress = self.context.stress + + tasks = [] + pool = Pool(4) + secs = f"00{'.' * (precision > 0)}{'0' * precision}" + + try: + with When(f"I loop through datetime range {hrs_range} starting from {date} in {step}min decrements"): + for hrs in range(*hrs_range, -1) if stress else (hrs_range[1], hrs_range[0]): + for mins in range(59, 0, -step) if stress else (59, 0): + datetime = f"{date} {str(hrs).zfill(2)}:{str(mins).zfill(2)}:{secs}" + expected = datetime + + with When(f"time is {datetime}"): + run_scenario(pool, tasks, Test(name=f"{hrs}:{mins}:{secs}", test=select_check_datetime), + kwargs=dict(datetime=datetime, precision=precision, timezone=timezone, + expected=expected)) + finally: + join(tasks) diff --git a/tests/testflows/datetime64_extended_range/tests/date_time_functions.py b/tests/testflows/datetime64_extended_range/tests/date_time_functions.py new file mode 100644 index 00000000000..d6c208ea0ee --- /dev/null +++ b/tests/testflows/datetime64_extended_range/tests/date_time_functions.py @@ -0,0 +1,1530 @@ +import time +import pytz +import itertools +from testflows.core import * +from dateutil.tz import tzlocal +import dateutil.relativedelta as rd +from datetime import datetime, timedelta + +from datetime64_extended_range.requirements.requirements import * +from datetime64_extended_range.common import * +from datetime64_extended_range.tests.common import * + + +@TestScenario +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_toTimeZone("1.0") +) +def to_time_zone(self): + """Check the toTimeZone() function with DateTime64 extended range. + """ + stress = self.context.stress + timezones = timezones_range(stress) + + for year in years_range(stress): + with Given("I select datetimes in a year"): + datetimes = select_dates_in_year(year=year, stress=stress) + + for dt in datetimes: + for tz1, tz2 in itertools.product(timezones, timezones): + with Example(f"{dt} {tz1} -> {tz2}"): + with By("Computing expected output using pytz"): + dt_local = pytz.timezone(tz1).localize(dt) + dt_transformed = dt_local.astimezone(pytz.timezone(tz2)) + tz2_expected = dt_transformed.strftime("%Y-%m-%d %H:%M:%S") + with And("Forming a toTimeZone ClickHouse query"): + tz1_query = dt_local.strftime("%Y-%m-%d %H:%M:%S") + query = f"SELECT toTimeZone(toDateTime64('{tz1_query}', 0, '{tz1}'), '{tz2}')" + with Then(f"I execute query", flags=TE): + exec_query(request=query, expected=f"{tz2_expected}") + + +@TestOutline +def to_date_part(self, py_func, ch_func): + """Check the toYear/toMonth/toQuarter functions with DateTime64 extended range. + """ + stress = self.context.stress + + for year in years_range(stress): + with Given(f"I choose datetimes in {year}"): + datetimes = select_dates_in_year(year=year, stress=stress) + timezones = timezones_range(stress) + + with When("I check each of the datetimes"): + for dt in datetimes: + for tz1, tz2 in itertools.product(timezones, timezones): + with Example(f"{dt} {tz1}, {tz2}"): + with Given("I compute expected output using pytz"): + with By(f"localizing {dt} using {tz1} timezone"): + time_tz1 = pytz.timezone(tz1).localize(dt) + with And(f"converting {tz1} local datetime {dt} to {tz2} timezone"): + time_tz2 = time_tz1.astimezone(pytz.timezone(tz2)) + with And(f"calling the '{py_func}' method of the datetime object to get expected result"): + result = eval(f"time_tz2.{py_func}") + expected = f"{result}" + with And(f"Forming a {ch_func} ClickHouse query"): + dt_str = dt.strftime("%Y-%m-%d %H:%M:%S") + query = f"SELECT {ch_func}(toDateTime64('{dt_str}', 0, '{tz1}'), '{tz2}')" + with Then(f"I execute query that uses '{ch_func}' function"): + exec_query(request=query, expected=f"{expected}") + + +@TestScenario +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_toYear("1.0"), + RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_toRelativeYearNum("1.0") +) +def to_year(self): + """Check the toYear() and toRelativeYearNum() [which is just an alias for toYear] + function with DateTime64 extended range. + """ + to_date_part(py_func="year", ch_func="toYear") + + +@TestScenario +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_toMonth("1.0") +) +def to_month(self): + """Check the toMonth() function with DateTime64 extended range. + """ + to_date_part(py_func="month", ch_func="toMonth") + + +@TestScenario +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_toQuarter("1.0") +) +def to_quarter(self): + """Check the toQuarter() function with DateTime64 extended range + by comparing the output of the toQuarter() function with + the value of the 'month' attribute of the datetime object + divided by 3 (because each quarter has 3 month) plus 1 + (because we starting the count from 1). + """ + to_date_part(py_func="month//3 + 1", ch_func="toQuarter") + + +@TestOutline +def to_day_of(self, py_func, ch_func): + """Check the toDayOf....() functions with DateTime64 extended range. + """ + stress = self.context.stress + + for year in years_range(stress): + with Given(f"I choose datetimes in {year}"): + datetimes = select_dates_in_year(year=year, stress=stress) + timezones = timezones_range(stress) + + with When("I check each of the datetimes"): + for dt in datetimes: + for tz1, tz2 in itertools.product(timezones, timezones): + with Example(f"{dt} {tz1} -> {tz2}"): + with By("Computing expected result using pytz"): + time_tz1 = pytz.timezone(tz1).localize(dt) + time_tz2 = time_tz1.astimezone(pytz.timezone(tz2)) + result = eval(f"time_tz2.timetuple().{py_func}") + expected = f"{result}" + with And(f"Forming a {ch_func} ClickHouse query"): + dt_str = dt.strftime("%Y-%m-%d %H:%M:%S") + query = f"SELECT {ch_func}(toDateTime64('{dt_str}', 0, '{tz1}'), '{tz2}')" + with Then(f"I execute {ch_func} query"): + exec_query(request=query, expected=f"{expected}") + + +@TestScenario +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_toDayOfYear("1.0") +) +def to_day_of_year(self): + """Check toDayOfYear() function with DateTime64 extended range date time. + """ + to_day_of(py_func="tm_yday", ch_func="toDayOfYear") + + +@TestScenario +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_toDayOfMonth("1.0") +) +def to_day_of_month(self): + """Check toDayOfMonth() function with DateTime64 extended range date time. + """ + to_day_of(py_func="tm_mday", ch_func="toDayOfMonth") + + +@TestScenario +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_toDayOfWeek("1.0") +) +def to_day_of_week(self): + """Check toDayOfWeek() function with DateTime64 extended range date time. + """ + to_day_of(py_func="tm_wday", ch_func="toDayOfWeek") + + +@TestOutline +def to_time_part(self, py_func, ch_func): + """Check the functions like toHour/toMinute/toSecond with DateTime64 extended range. + """ + stress = self.context.stress + + for year in years_range(stress): + with Given(f"I choose datetimes in {year}"): + datetimes = select_dates_in_year(year=year, stress=stress) + timezones = timezones_range(stress) + + with When("I check each of the datetimes"): + for dt in datetimes: + for tz1, tz2 in itertools.product(timezones, timezones): + with Example(f"{dt} {tz1} -> {tz2}"): + with By("computing expected result using pytz"): + time_tz1 = pytz.timezone(tz1).localize(dt) + time_tz2 = time_tz1.astimezone(pytz.timezone(tz2)) + result = eval(f"time_tz2.{py_func}") + expected = f"{result}" + with And("forming a ClickHouse query"): + dt_str = dt.strftime("%Y-%m-%d %H:%M:%S") + query = f"SELECT {ch_func}(toDateTime64('{dt_str}', 0, '{tz1}'), '{tz2}')" + with Then("I execute query"): + exec_query(request=query, expected=f"{expected}") + + +@TestScenario +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_toHour("1.0") +) +def to_hour(self): + """Check toHour() function with DateTime64 extended range date time. + """ + to_time_part(py_func="hour", ch_func="toHour") + + +@TestScenario +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_toMinute("1.0") +) +def to_minute(self): + """Check toMinute() function with DateTime64 extended range date time. + """ + to_time_part(py_func="minute", ch_func="toMinute") + + +@TestScenario +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_toSecond("1.0") +) +def to_second(self): + """Check toSecond() function with DateTime64 extended range date time. + """ + to_time_part(py_func="second", ch_func="toSecond") + + +@TestScenario +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_toUnixTimestamp("1.0") +) +def to_unix_timestamp(self): + """Check the toUnixTimestamp() function with DateTime64 extended range + """ + stress = self.context.stress + + for year in years_range(stress): + with Given(f"I choose datetimes in {year}"): + datetimes = select_dates_in_year(year=year, stress=stress) + timezones = timezones_range(stress) + + with When("I check each of the datetimes"): + for dt in datetimes: + for tz in timezones: + with Example(f"{dt} {tz}"): + with By("computing expected result using python"): + dt_str = dt.strftime("%Y-%m-%d %H:%M:%S") + expected = f"{int(time.mktime(datetime.datetime.now().timetuple()))}" + with And("forming a ClickHouse query"): + query = f"SELECT toUnixTimestamp(toDateTime64('{dt_str}', 0, '{tz}'))" + with Then("I execute query"): + exec_query(request=query, expected=expected) + + +@TestScenario +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_toStartOfYear("1.0") +) +def to_start_of_year(self): + """Check the functions toStartOfYear with DateTime64 extended range.""" + stress = self.context.stress + timezones = timezones_range(stress) + + for year in years_range(stress): + with Given(f"I choose datetimes in {year}"): + datetimes = select_dates_in_year(year=year, stress=stress) + + with When("I check each of the datetimes"): + for dt in datetimes: + for tz1, tz2 in itertools.product(timezones, timezones): + with Example(f"{dt} {tz1} -> {tz2}"): + with By("computing expected time using python"): + time_tz1 = pytz.timezone(tz1).localize(dt) + time_tz2 = time_tz1.astimezone(pytz.timezone(tz2)) + expected = f"{time_tz2.year}-01-01" + with And("forming ClickHouse query"): + dt_str = dt.strftime("%Y-%m-%d %H:%M:%S") + query = f"SELECT toStartOfYear(toDateTime64('{dt_str}', 0, '{tz1}'), '{tz2}')" + with Then("I execute query"): + exec_query(request=query, expected=f"{expected}") + + +def iso_year_start(dt): + """Helper to find the beginning of iso year.""" + dt_s = datetime.datetime(dt.year-1, 12, 23, 0, 0, 0) + while dt_s.isocalendar()[0] != dt.year: + dt_s += datetime.timedelta(days=1) + return dt_s + + +@TestScenario +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_toStartOfISOYear("1.0") +) +def to_start_of_iso_year(self): + """Check the functions toStartOfISOYear with DateTime64 extended range.""" + stress = self.context.stress + timezones = timezones_range(stress) + + for year in years_range(stress): + with Given(f"I choose datetimes in {year}"): + datetimes = select_dates_in_year(year=year, stress=stress) + + with When("I check each of the datetimes"): + for dt in datetimes: + for tz in timezones: + with Example(f"{dt} {tz}"): + with By("Computing expected result using Python"): + expected = iso_year_start(dt) + with And("Forming a toStartOfISOYear ClickHouse query"): + dt_str = dt.strftime("%Y-%m-%d %H:%M:%S") + query = f"SELECT toStartOfISOYear(toDateTime64('{dt_str}', 0, '{tz}'))" + with Then("I execute toStartOfISOYear query"): + exec_query(request=query, expected=f"{expected.strftime('%Y-%m-%d')}") + + +@TestScenario +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_toStartOfQuarter("1.0") +) +def to_start_of_quarter(self): + """Check the functions toStartOfQuarter with + DateTime64 extended range. + """ + stress = self.context.stress + timezones = timezones_range(stress) + + for year in years_range(stress): + with Given(f"I choose datetimes in {year}"): + datetimes = select_dates_in_year(year=year, stress=stress) + with When("I check each of the datetimes"): + for dt in datetimes: + for tz1, tz2 in itertools.product(timezones, timezones): + with Example(f"{dt} {tz1} -> {tz2}"): + with By("computing expected result with python"): + time_tz1 = pytz.timezone(tz1).localize(dt) + time_tz2 = time_tz1.astimezone(pytz.timezone(tz2)) + expected = f"{year}-{str(time_tz2.month//3 * 3 + 1).zfill(2)}-01" + with And("forming ClickHouse query"): + dt_str = dt.strftime("%Y-%m-%d %H:%M:%S") + query = f"SELECT toStartOfQuarter(toDateTime64('{dt_str}', 0, '{tz1}'), '{tz2}')" + with Then("I execute query"): + exec_query(request=query, expected=f"{expected}") + + +@TestScenario +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_toStartOfMonth("1.0") +) +def to_start_of_month(self): + """Check the functions toStartOfMonth with + DateTime64 extended range. + """ + stress = self.context.stress + timezones = timezones_range(stress) + + for year in years_range(stress=stress): + with Given(f"I choose datetimes in {year}"): + datetimes = select_dates_in_year(year=year, stress=stress) + with When("I check each of the datetimes"): + for dt in datetimes: + for tz1, tz2 in itertools.product(timezones, timezones): + with Example(f"{dt} {tz1} -> {tz2}"): + with By("computing expected result with python"): + time_tz1 = pytz.timezone(tz1).localize(dt) + time_tz2 = time_tz1.astimezone(pytz.timezone(tz2)) + expected = f"{time_tz2.strftime('%Y-%m')}-01" + with And("forming ClickHouse query"): + dt_str = dt.strftime("%Y-%m-%d %H:%M:%S") + query = f"SELECT toStartOfQuarter(toDateTime64('{dt_str}', 0, '{tz1}'), '{tz2}')" + with Then("I execute query"): + exec_query(request=query, expected=f"{expected}") + + +@TestScenario +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_toMonday("1.0") +) +def to_monday(self): + """Check the functions toMonday with + DateTime64 extended range. + """ + stress = self.context.stress + timezones = timezones_range(stress) + + for year in years_range(stress): + with Given(f"I choose datetimes in {year}"): + datetimes = select_dates_in_year(year=year, stress=stress) + with When("I check each of the datetimes"): + for dt in datetimes: + for tz1, tz2 in itertools.product(timezones, timezones): + with Example(f"{dt} {tz1} -> {tz2}"): + with By("computing expected result with python"): + time_tz1 = pytz.timezone(tz1).localize(dt) + time_tz2 = time_tz1.astimezone(pytz.timezone(tz2)) + expected_date = time_tz2 + datetime.timedelta(days=(-dt.weekday() if dt.weekday() <= 3 else 7 - dt.weekday())) + expected = f"{expected_date.strftime('%Y-%m-%d')}" + with And("forming ClickHouse query"): + dt_str = dt.strftime("%Y-%m-%d %H:%M:%S") + query = f"SELECT toMonday(toDateTime64('{dt_str}', 0, '{tz1}'), '{tz2}')" + with Then("I execute query"): + exec_query(request=query, expected=f"{expected}") + + +@TestScenario +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_toStartOfWeek("1.0") +) +def to_start_of_week(self): + """Check the functions toStartOfWeek with DateTime64 extended range.""" + stress = self.context.stress + timezones = timezones_range(stress) + + for year in years_range(stress): + with Given(f"I choose datetimes in {year}"): + datetimes = select_dates_in_year(year=year, stress=stress) + with When("I check each of the datetimes"): + for dt in datetimes: + for tz1, tz2 in itertools.product(timezones, timezones): + for mode in (0, 1): # mode - week beginning, either 0 (Sunday) or 1 (Monday) + with Example(f"{dt} {tz1} -> {tz2}"): + with By("computing expected result with python"): + time_tz1 = pytz.timezone(tz1).localize(dt) + time_tz2 = time_tz1.astimezone(pytz.timezone(tz2)) + expected_date = time_tz2 + datetime.timedelta( + days=(mode - dt.weekday() if dt.weekday() <= (3+mode) else (mode + 7) - dt.weekday())) + expected = f"{expected_date.strftime('%Y-%m-%d')}" + with And("forming ClickHouse query"): + dt_str = dt.strftime("%Y-%m-%d %H:%M:%S") + query = f"SELECT toStartOfWeek(toDateTime64('{dt_str}', 0, '{tz1}'), {mode}, '{tz2}')" + with Then("I execute query"): + exec_query(request=query, expected=f"{expected}") + + +@TestScenario +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_toStartOfDay("1.0") +) +def to_start_of_day(self): + """Check the functions toStartOfDay with DateTime64 extended range.""" + stress = self.context.stress + timezones = timezones_range(stress) + + for year in years_range(stress): + with Given(f"I choose datetimes in {year}"): + datetimes = select_dates_in_year(year=year, stress=stress) + with When("I check each of the datetimes"): + for dt in datetimes: + for tz in timezones: + with Example(f"{dt} {tz}"): + with By("computing expected result with python"): + expected = f"{dt.strftime('%Y-%m-%d')} 00:00:00" + with And("forming ClickHouse query"): + dt_str = dt.strftime("%Y-%m-%d %H:%M:%S") + query = f"SELECT toStartOfDay(toDateTime64('{dt_str}', 0, '{tz}'))" + with Then("I execute query"): + exec_query(request=query, expected=f"{expected}") + + +@TestScenario +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_toStartOfHour("1.0") +) +def to_start_of_hour(self): + """Check the functions toStartOfHour with DateTime64 extended range.""" + stress = self.context.stress + timezones = timezones_range(stress) + + for year in years_range(stress): + with Given(f"I choose datetimes in {year}"): + datetimes = select_dates_in_year(year=year, stress=stress) + + with When("I check each of the datetimes"): + for dt in datetimes: + for tz in timezones: + with Example(f"{dt} {tz}"): + with By("computing expected result with python"): + expected = f"{dt.strftime('%Y-%m-%d %H')}:00:00" + with And("forming ClickHouse query"): + dt_str = dt.strftime("%Y-%m-%d %H:%M:%S") + query = f"SELECT toStartOfHour(toDateTime64('{dt_str}', 0, '{tz}'))" + with Then("I execute query"): + exec_query(request=query, expected=f"{expected}") + + +@TestScenario +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_toStartOfMinute("1.0") +) +def to_start_of_minute(self): + """Check the functions toStartOfMinute with DateTime64 extended range.""" + stress = self.context.stress + timezones = timezones_range(stress) + + for year in years_range(stress): + with Given(f"I choose datetimes in {year}"): + datetimes = select_dates_in_year(year=year, stress=stress) + + with When("I check each of the datetimes"): + for dt in datetimes: + for tz in timezones: + with Example(f"{dt} {tz}"): + with By("computing expected result with python"): + expected = f"{dt.strftime('%Y-%m-%d %H:%M')}:00" + with And("forming ClickHouse query"): + dt_str = dt.strftime("%Y-%m-%d %H:%M:%S") + query = f"SELECT toStartOfMinute(toDateTime64('{dt_str}', 0, '{tz}'))" + with Then("I execute query"): + exec_query(request=query, expected=f"{expected}") + + +@TestScenario +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_toStartOfSecond("1.0") +) +def to_start_of_second(self): + """Check the functions toStartOfSecond with DateTime64 extended range.""" + stress = self.context.stress + timezones = timezones_range(stress) + + for year in years_range(stress=stress): + with Given(f"I choose datetimes in {year}"): + datetimes = select_dates_in_year(year=year, stress=stress, microseconds=True) + + with When("I check each of the datetimes"): + for dt in datetimes: + for tz in timezones: + with Example(f"{dt} {tz}"): + with By("computing expected result with python"): + expected = f"{dt.strftime('%Y-%m-%d %H:%M:%S')}.000000" + with And("forming ClickHouse query"): + dt_str = dt.strftime("%Y-%m-%d %H:%M:%S.%f") + query = f"SELECT toStartOfSecond(toDateTime64('{dt_str}', 6, '{tz}'))" + with Then("I execute query"): + exec_query(request=query, expected=f"{expected}") + + +@TestOutline +def to_start_of_minutes_interval(self, interval, func): + """Check the functions like toStartOf....Minute with DateTime64 extended range.""" + stress = self.context.stress + timezones = timezones_range(stress) + + for year in years_range(stress=stress): + with Given(f"I choose datetimes in {year}"): + datetimes = select_dates_in_year(year=year, stress=stress, microseconds=True) + + with When("I check each of the datetimes"): + for dt in datetimes: + for tz in timezones: + with Example(f"{dt} {tz}"): + with By("Computing expected result using python"): + mins = dt.minute // interval * interval + expected = f"{dt.strftime('%Y-%m-%d %H:')}{str(mins).zfill(2)}:00" + with And(f"Forming a {func} query to ClickHouse"): + dt_str = dt.strftime("%Y-%m-%d %H:%M:%S") + query = f"SELECT {func}(toDateTime64('{dt_str}', 0, '{tz}'))" + with Then(f"I execute {func} query"): + exec_query(request=query, expected=f"{expected}") + + +@TestScenario +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_toStartOfFiveMinute("1.0") +) +def to_start_of_five_minute(self): + """Check the toStartOfFiveMinute with DateTime64 extended range.""" + to_start_of_minutes_interval(interval=5, func="toStartOfFiveMinute") + + +@TestScenario +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_toStartOfTenMinutes("1.0") +) +def to_start_of_ten_minutes(self): + """Check the toStartOfTenMinutes with DateTime64 extended range.""" + to_start_of_minutes_interval(interval=10, func="toStartOfTenMinutes") + + +@TestScenario +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_toStartOfFifteenMinutes("1.0") +) +def to_start_of_fifteen_minutes(self): + """Check the toStartOfFifteenMinutes with DateTime64 extended range.""" + to_start_of_minutes_interval(interval=15, func="toStartOfFifteenMinutes") + + +@TestScenario +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_timeSlot("1.0") +) +def time_slot(self): + """Check the timeSlot with DateTime64 extended range.""" + to_start_of_minutes_interval(interval=30, func="timeSlot") + + +def to_start_of_interval_helper(dt: datetime.datetime, interval_type, interval_value): + """A helper to switch through all possible intervals. Computes the interval beginning depending on + interval_type and interval_value, returns string expected to be returned by ClickHouse. + :param dt: datetime to be checked, datetime.datetime + :param interval_type: interval type selector, String + :param interval_value: interval size, int + """ + intervals_in_seconds = {"SECOND": 1, "MINUTE": 60, "HOUR": 3600, "DAY": 68400, "WEEK": 604800} + zero_datetime = datetime.datetime(1970, 1, 1, 0, 0, 0) + delta = dt - zero_datetime + + if interval_type in intervals_in_seconds.keys(): + divisor = interval_value * intervals_in_seconds[interval_type] + retval = (zero_datetime + datetime.timedelta(seconds=(delta.seconds // divisor * divisor))) + if interval_type == "WEEK": + return retval.strftime("%Y-%m-%d") + return retval.strftime("%Y-%m-%d %H:%M:%S") + + elif interval_type == "MONTH": + diff = (dt.year - zero_datetime.year) * 12 + (dt.month - zero_datetime.month) + result_diff = diff // interval_value * interval_value + return (zero_datetime + rd.relativedelta(months=result_diff)).strftime("%Y-%m-%d") + + elif interval_type == "QUARTER": + diff = (dt.year - zero_datetime.year) * 4 + (dt.month // 4 - zero_datetime.month // 4) + result_diff = diff // interval_value * interval_value + return (zero_datetime + rd.relativedelta(months=result_diff*4)).strftime("%Y-%m-%d") + + elif interval_type == "YEAR": + result_diff = (dt.year - zero_datetime.year) // interval_value * interval_value + return (zero_datetime + rd.relativedelta(years=result_diff)).strftime("%Y-%m-%d") + + +@TestScenario +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_toStartOfInterval("1.0") +) +def to_start_of_interval(self): + """Check the toStartOfInterval with DateTime64 extended range. + """ + stress = self.context.stress + timezones = timezones_range(stress) + + intervals_testing_ranges = {"SECOND": range(1, 15), "MINUTE": range(1, 15), "HOUR": range(1, 10), "DAY": (1, 5, 10), + "WEEK": range(1, 5), "MONTH": range(1, 6), "QUARTER": range(1, 4), "YEAR": range(1, 5)} + + for year in years_range(stress=stress): + with Given(f"I choose datetimes in {year}"): + datetimes = select_dates_in_year(year=year, stress=stress) + + with When("I check each of the datetimes"): + for dt in datetimes: + for tz in timezones: + for interval in intervals_testing_ranges.keys(): + for value in intervals_testing_ranges[interval]: + with Example(f"{dt} {tz} {interval}: {value}"): + with By("Computing expected result using python"): + expected = to_start_of_interval_helper(dt, interval, value) + with And(f"Forming a toStartOfInterval() query to ClickHouse"): + dt_str = dt.strftime("%Y-%m-%d %H:%M:%S") + query = f"SELECT toStartOfInterval(toDateTime64('{dt_str}', 0, '{tz}'), INTERVAL {value} {interval})" + with Then(f"I execute toStartOfInterval() query"): + exec_query(request=query, expected=f"{expected}") + + +@TestOutline +def to_iso(self, func, isocalendar_pos): + """Check the toISOYear/Week functions with DateTime64 extended range.""" + stress = self.context.stress + timezones = timezones_range(stress) + + for year in years_range(stress=stress): + with Given(f"I choose datetimes in {year}"): + datetimes = select_dates_in_year(year=year, stress=stress, microseconds=True) + + with When("I check each of the datetimes"): + for dt in datetimes: + for tz in timezones: + with Example(f"{dt} {tz}"): + with By("computimg expected result uning python"): + expected = f"{dt.isocalendar()[isocalendar_pos]}" + with And("forming ClickHouse query"): + dt_str = dt.strftime("%Y-%m-%d %H:%M:%S") + query = f"SELECT {func}(toDateTime64('{dt_str}', 0, '{tz}'))" + with Then("I execute query"): + exec_query(request=query, expected=f"{expected}") + + +@TestScenario +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_toISOYear("1.0") +) +def to_iso_year(self): + """Check the toISOYear function with DateTime64 extended range.""" + to_iso(func="toISOYear", isocalendar_pos=0) + + +@TestScenario +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_toISOWeek("1.0") +) +def to_iso_week(self): + """Check the toISOWeek function with DateTime64 extended range.""" + to_iso(func="toISOWeek", isocalendar_pos=1) + + +@TestScenario +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_toTime("1.0") +) +def to_time(self): + """Check the toTime function with DateTime64 extended range.""" + stress = self.context.stress + timezones = timezones_range(stress) + + for year in years_range(stress=stress): + with Given(f"I choose datetimes in {year}"): + datetimes = select_dates_in_year(year=year, stress=stress, microseconds=True) + + with When("I check each of the datetimes"): + for dt in datetimes: + for tz in timezones: + with Example(f"{dt} {tz}"): + with By("computing expected result using python"): + expected = f"1970-01-02 {dt.strftime('%H:%M:%S')}" + with And("forming ClickHouse query"): + dt_str = dt.strftime("%Y-%m-%d %H:%M:%S") + query = f"SELECT toTime(toDateTime64('{dt_str}', 0, '{tz}'))" + with Then("I execute query"): + exec_query(request=query, expected=f"{expected}") + + +@TestScenario +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_toRelativeQuarterNum("1.0") +) +def to_relative_quarter_num(self): + """Check the toRelativeQuarterNum function with DateTime64 extended range.""" + stress = self.context.stress + timezones = timezones_range(stress) + + for year in years_range(stress=stress): + with Given(f"I choose datetimes in {year}"): + datetimes = select_dates_in_year(year=year, stress=stress, microseconds=True) + + with When("I check each of the datetimes"): + for dt in datetimes: + for tz in timezones: + with Example(f"{dt} {tz}"): + with By("computing expected result using python"): + expected = f"{(year-1970)*4 + (dt.month - 1) // 3}" + with And("forming ClickHouse query"): + dt_str = dt.strftime("%Y-%m-%d %H:%M:%S") + query = f"SELECT toRelativeQuarterNum(toDateTime64('{dt_str}', 0, '{tz}'))" + with Then("I execute query"): + exec_query(request=query, expected=f"{expected}") + + +@TestScenario +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_toRelativeWeekNum("1.0") +) +def to_relative_week_num(self): + """Check the toRelativeWeekNum function with DateTime64 extended range.""" + stress = self.context.stress + timezones = timezones_range(stress) + + for year in years_range(stress=stress): + with Given(f"I choose datetimes in {year}"): + datetimes = select_dates_in_year(year=year, stress=stress, microseconds=True) + with When("I check each of the datetimes"): + for dt in datetimes: + for tz in timezones: + with Example(f"{dt} {tz}"): + with By("computing expected result using python"): + week_num = ((dt + datetime.timedelta(days=8) - datetime.timedelta(days=dt.weekday())) - datetime.datetime(1970, 1, 1, 0, 0, 0)).days // 7 + expected = f"{week_num}" + with And("forming ClickHouse query"): + dt_str = dt.strftime("%Y-%m-%d %H:%M:%S") + query = f"SELECT toRelativeWeekNum(toDateTime64('{dt_str}', 0, '{tz}'))" + with Then("I execute query"): + exec_query(request=query, expected=f"{expected}") + + +@TestScenario +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_toRelativeMonthNum("1.0") +) +def to_relative_month_num(self): + """Check the toRelativeMonthNum function with DateTime64 extended range.""" + stress = self.context.stress + timezones = timezones_range(stress) + + for year in years_range(stress=stress): + with Given(f"I choose datetimes in {year}"): + datetimes = select_dates_in_year(year=year, stress=stress, microseconds=True) + + with When("I check each of the datetimes"): + for dt in datetimes: + for tz in timezones: + with Example(f"{dt} {tz}"): + with By("computing expected result using python"): + month_num = (year - 1970) * 12 + dt.month + expected = f"{month_num}" + with And("forming ClickHouse query"): + dt_str = dt.strftime("%Y-%m-%d %H:%M:%S") + query = f"SELECT toRelativeMonthNum(toDateTime64('{dt_str}', 0, '{tz}'))" + with Then("I execute query"): + exec_query(request=query, expected=f"{expected}") + + +@TestScenario +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_toRelativeDayNum("1.0") +) +def to_relative_day_num(self): + """Check the toRelativeDayNum function with DateTime64 extended range.""" + stress = self.context.stress + timezones = timezones_range(stress) + + for year in years_range(stress=stress): + with Given(f"I choose datetimes in {year}"): + datetimes = select_dates_in_year(year=year, stress=stress, microseconds=True) + + with When("I check each of the datetimes"): + for dt in datetimes: + for tz in timezones: + with Example(f"{dt} {tz}"): + with By("Computing the expected result using python"): + day_num = (dt - datetime.datetime(1970, 1, 1, 0, 0, 0)).days + expected = f"{day_num}" + with And(f"Forming a toRelativeDayNum query to ClickHouse"): + dt_str = dt.strftime("%Y-%m-%d %H:%M:%S") + query = f"SELECT toRelativeDayNum(toDateTime64('{dt_str}', 0, '{tz}'))" + with When("I execute toRelativeDayNum query"): + exec_query(request=query, expected=f"{expected}") + + +@TestOutline +def to_relative_time(self, divisor, func): + """Check the toRelative[Hour/Minute/Second]Num functions + with DateTime64 extended range. + """ + stress = self.context.stress + timezones = timezones_range(stress) + + for year in years_range(stress=stress): + with Given(f"I choose datetimes in {year}"): + datetimes = select_dates_in_year(year=year, stress=stress, microseconds=True) + + with When("I check each of the datetimes"): + for dt in datetimes: + for tz in timezones: + with Example(f"{dt} {tz}"): + with By("Computing the expected result using python"): + result = (dt - datetime.datetime(1970, 1, 1, 0, 0, 0)).total_seconds() // divisor + expected = f"{result}" + with And(f"Forming a {func} query to ClickHouse"): + dt_str = dt.strftime("%Y-%m-%d %H:%M:%S") + query = f"SELECT {func}(toDateTime64('{dt_str}', 0, '{tz}'))" + with Then(f"I execute {func} query"): + exec_query(request=query, expected=f"{expected}") + + +@TestScenario +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_toRelativeHourNum("1.0") +) +def to_relative_hour_num(self): + """Check the toRelativeHourNum function + with DateTime64 extended range. + """ + to_relative_time(func="toRelativeHourNum", divisor=3600) + + +@TestScenario +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_toRelativeMinuteNum("1.0") +) +def to_relative_minute_num(self): + """Check the toRelativeMinuteNum function + with DateTime64 extended range. + """ + to_relative_time(func="toRelativeMinuteNum", divisor=60) + + +@TestScenario +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_toRelativeSecondNum("1.0") +) +def to_relative_second_num(self): + """Check the toRelativeSecondNum function + with DateTime64 extended range. + """ + to_relative_time(func="toRelativeSecondNum", divisor=1) + + +def to_week_compute_expected(dt: datetime.datetime, mode: int, ret_year=False): + """Helper to get the expected value for testing toWeek(). + Due to necessity to manually check 10 workmodes, the subroutine was removed from to_week() + """ + year = dt.year + + ex = datetime.datetime(year, 1, 1) + j1_weekday = ex.weekday() + + while ex.weekday() != 0: + ex += datetime.timedelta(days=1) + first_monday = ex.day-1 + + ex = datetime.datetime(year, 1, 1) + while ex.weekday() != 6: + ex += datetime.timedelta(days=1) + first_sunday = ex.day-1 + + if mode == 0: + # First day of week: Sunday, Week 1 is the first week with Sunday, range 0-53 + expected = (dt - datetime.datetime(year, 1, 1) - datetime.timedelta(days=first_sunday)).days // 7 + 1 + + elif mode == 1: + # First day of week: Monday, Week 1 is the first week containing 4 or more days, range 0-53 + if j1_weekday <= 3: + expected = (dt - datetime.datetime(year, 1, 1) + datetime.timedelta(days=7+j1_weekday)).days // 7 + else: + expected = (dt - datetime.datetime(year, 1, 1) + datetime.timedelta(days=j1_weekday)).days // 7 + + elif mode == 2: + # First day of week: Sunday, Week 1 is the first week with Sunday, range 1-53 + expected = (dt - datetime.datetime(year, 1, 1) - datetime.timedelta(days=first_sunday)).days // 7 + 1 + if expected == 0: + return to_week_compute_expected(datetime.datetime(dt.year-1, 12, 31), 2) + + elif mode == 3: + # First day of week: Monday, Week 1 is the first week containing 4 or more days, range 1-53 + if j1_weekday <= 3: + expected = (dt - datetime.datetime(year, 1, 1) + datetime.timedelta(days=7+j1_weekday)).days // 7 + else: + expected = (dt - datetime.datetime(year, 1, 1) + datetime.timedelta(days=j1_weekday)).days // 7 + if expected == 0: + return to_week_compute_expected(datetime.datetime(dt.year-1, 12, 31), 3) + + elif mode == 4: + # First day of week: Sunday, Week 1 is the first week containing 4 or more days, range 0-53 + if j1_weekday <= 3: + expected = (dt - datetime.datetime(year, 1, 1) + datetime.timedelta(days=8+j1_weekday)).days // 7 + else: + expected = (dt - datetime.datetime(year, 1, 1) + datetime.timedelta(days=j1_weekday+1)).days // 7 + + elif mode == 5: + # First day of week: Monday, Week 1 is the first week with a Monday, range 0-53 + expected = (dt - datetime.datetime(year, 1, 1) - datetime.timedelta(days=first_monday)).days // 7 + 1 + + elif mode == 6: + # First day of week: Sunday, Week 1 is the first week containing 4 or more days, range 1-53 + if j1_weekday <= 3: + expected = (dt - datetime.datetime(year, 1, 1) + datetime.timedelta(days=8+j1_weekday)).days // 7 + else: + expected = (dt - datetime.datetime(year, 1, 1) + datetime.timedelta(days=j1_weekday+1)).days // 7 + if expected == 0: + return to_week_compute_expected(datetime.datetime(dt.year-1, 12, 31), 6) + + elif mode == 7: + # First day of week: Monday, Week 1 is the first week with a Monday, range 1-53 + expected = (dt - datetime.datetime(year, 1, 1) - datetime.timedelta(days=first_monday)).days // 7 + 1 + if expected == 0: + return to_week_compute_expected(datetime.datetime(dt.year-1, 12, 31), 7) + + elif mode == 8: + # First day of week: Sunday, Week 1 is the week containing January 1, range 1-53 + expected = (dt - datetime.datetime(year, 1, 1) + datetime.timedelta(days=(j1_weekday+1)%7)).days // 7 + 1 + + elif mode == 9: + # First day of week: Monday, Week 1 is the week containing January 1, range 1-53 + expected = (dt - datetime.datetime(year, 1, 1) + datetime.timedelta(days=j1_weekday%7)).days // 7 + 1 + + return f"{dt.year}{str(expected).zfill(2)}" if ret_year else f"{expected}" + + +@TestOutline +def to_week_year_week(self, clh_func, ret_year): + """Check the toWeek/toYearWeek function with DateTime64 extended range. + For detailed info on work modes and description, see + https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#toweekdatemode + :param self: current test + :param clh_func: ClickHouse function to be called, string + :param ret_year: toWeek/toYearWeek selector, Boolean + """ + stress = self.context.stress + timezones = timezones_range(stress) + + for year in years_range(stress): + with Given(f"I choose datetimes in {year}"): + datetimes = select_dates_in_year(year=year, stress=stress) + + with When("I check each of the datetimes"): + for dt in datetimes: + for tz in timezones: + for mode in range(0, 10): + with Example(f"{dt} {tz}"): + with By("Computing expected output using python"): + expected = to_week_compute_expected(dt=dt, mode=mode, ret_year=ret_year) + with And(f"Forming a {clh_func} query"): + dt_str = dt.strftime("%Y-%m-%d %H:%M:%S") + query = f"SELECT {clh_func}(toDateTime64('{dt_str}', 0, '{tz}'), {mode})" + with When(f"I execute the {clh_func} query"): + exec_query(request=query, expected=f"{expected}") + + +@TestScenario +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_toWeek("1.0") +) +def to_week(self): + """Check the toWeek function with DateTime64 extended range.""" + to_week_year_week(clh_func="toWeek", ret_year=False) + + +@TestScenario +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_toYearWeek("1.0") +) +def to_year_week(self): + """Check the toYearWeek function with DateTime64 extended range.""" + to_week_year_week(clh_func="toYearWeek", ret_year=True) + + +@TestScenario +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_toYYYYMM("1.0") +) +def to_yyyymm(self): + """Check the toYYYYMM() function with + DateTime64 extended range. + """ + stress = self.context.stress + timezones = timezones_range(stress) + + for year in years_range(stress): + with Given(f"I choose datetimes in {year}"): + datetimes = select_dates_in_year(year=year, stress=stress) + + with When("I check each of the datetimes"): + for dt in datetimes: + for tz in timezones: + with Example(f"{dt} {tz}"): + with By("computing expected result in python"): + expected = f"{dt.strftime('%Y%m')}" + with And("forming ClickHouse query"): + dt_str = dt.strftime("%Y-%m-%d %H:%M:%S") + query = f"SELECT toYYYYMM(toDateTime64('{dt_str}', 0, '{tz}'))" + with Then("I execute query"): + exec_query(request=query, expected=f"{expected}") + + +@TestScenario +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_toYYYYMMDD("1.0") +) +def to_yyyymmdd(self): + """Check the toYYYYMMDD() function with + DateTime64 extended range. + """ + stress = self.context.stress + timezones = timezones_range(stress) + + for year in years_range(stress): + with Given(f"I choose datetimes in {year}"): + datetimes = select_dates_in_year(year=year, stress=stress) + + with When("I check each of the datetimes"): + for dt in datetimes: + for tz in timezones: + with Example(f"{dt} {tz}"): + with By("computing expected result in python"): + expected = f"{dt.strftime('%Y%m%d')}" + with And("forming ClickHouse query"): + dt_str = dt.strftime("%Y-%m-%d %H:%M:%S") + query = f"SELECT toYYYYMMDD(toDateTime64('{dt_str}', 0, '{tz}'))" + with Then("I execute query", description=f"expected {expected}", flags=TE): + exec_query(request=query, expected=f"{expected}") + + +@TestScenario +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_toYYYYMMDDhhmmss("1.0") +) +def to_yyyymmddhhmmss(self): + """Check the toYYYYMMDDhhmmss() function with + DateTime64 extended range. + """ + stress = self.context.stress + timezones = timezones_range(stress) + + for year in years_range(stress): + with Given(f"I choose datetimes in {year}"): + datetimes = select_dates_in_year(year=year, stress=stress) + + with When("I check each of the datetimes"): + for dt in datetimes: + for tz in timezones: + with Example(f"{dt} {tz}"): + with By("computing expected result in python"): + expected = f"{dt.strftime('%Y%m%d%H%M%S')}" + with And("forming ClickHouse query"): + dt_str = dt.strftime("%Y-%m-%d %H:%M:%S") + query = f"SELECT toYYYYMMDDhhmmss(toDateTime64('{dt_str}', 0, '{tz}'))" + with Then("I execute query"): + exec_query(request=query, expected=f"{expected}") + + +@TestScenario +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_now("1.0") +) +def now(self): + """Check the now() conversion to DateTime64 extended range. + In this test, we cannot assure that pytz now() and ClickHouse now() will be executed at the same time, so we need + a 30-second error tolerance to test this functionality + """ + stress = self.context.stress + timezones = timezones_range(stress) + + for tz in timezones: + with Given("I record current time and localize it"): + dt = datetime.datetime.now(tzlocal()) + dt = dt.astimezone(pytz.timezone(tz)) + + with Example(f"{dt} {tz}"): + with When("I execute query and format its result to string"): + r = self.context.node.query(f"SELECT toDateTime64(now(), 0, '{tz}')") + query_result = r.output + received_dt = datetime.datetime.strptime(query_result, '%Y-%m-%d %H:%M:%S') + + with Then("I compute the difference between ClickHouse query result and pytz result"): + dt = dt.replace(tzinfo=None) + if dt < received_dt: + diff = (received_dt - dt).total_seconds() + else: + diff = (dt - received_dt).total_seconds() + + with Finally(f"I expect {diff} < 30 seconds"): + assert diff < 30, error() + + +@TestScenario +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_today("1.0") +) +def today(self): + """Check the today() conversion to DateTime64 extended range. + """ + stress = self.context.stress + timezones = timezones_range(stress) + + for tz in timezones: + with Given("I record current time and localize it"): + dt = datetime.datetime.now(tzlocal()) + dt = dt.astimezone(pytz.timezone(tz)) + + with Example(f"{dt} {tz}"): + with When("I execute query and format its result to string"): + r = self.context.node.query(f"SELECT toDateTime64(today(), 0, '{tz}')") + query_result = r.output + received_dt = datetime.datetime.strptime(query_result, '%Y-%m-%d %H:%M:%S') + + with Then("I compute the difference between ClickHouse query result and pytz result"): + dt = dt.replace(tzinfo=None) + if dt < received_dt: + diff = (received_dt - dt).total_seconds() + else: + diff = (dt - received_dt).total_seconds() + + with Finally(f"I expect {diff} < 24 hours"): + assert diff < 86400, error() + + +@TestScenario +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_yesterday("1.0") +) +def yesterday(self): + """Check the yesterday() conversion to DateTime64 extended range. + """ + + stress = self.context.stress + timezones = timezones_range(stress) + + for tz in timezones: + with Given("I record current time and localize it"): + dt = datetime.datetime.now(tzlocal()) + dt = dt.astimezone(pytz.timezone(tz)) + + with Example(f"{dt} {tz}"): + with When("I execute query and format its result to string"): + r = self.context.node.query(f"SELECT toDateTime64(yesterday(), 0, '{tz}')") + query_result = r.output + received_dt = datetime.datetime.strptime(query_result, '%Y-%m-%d %H:%M:%S') + + with Then("I compute the difference between ClickHouse query result and pytz result"): + dt = dt.replace(tzinfo=None) + dt -= datetime.timedelta(days=1) + if dt < received_dt: + diff = (received_dt - dt).total_seconds() + else: + diff = (dt - received_dt).total_seconds() + + with Finally(f"I expect {diff} < 48 hours (172800 seconds)"): + assert diff < 172800, error() + + +@TestOutline +def add_subtract_functions(self, clh_func, py_key, test_range, years_padding=(1, 1), modifier=1, mult=1): + """Check the addYears/addMonths/addWeeks/addDays/addHours/addMinutes/addSeconds with DateTime64 extended range. + Calculating expected result using eval() to avoid writing 9000+ comparisons and just parse string as object field name. + :param self: self + :param clh_func: ClickHouse function to be called, string + :param py_key: relativedelta parameter used to modify datetime, string + :param test_range: range of increments to be used, any iterable ints structure + :param years_padding: a number of years to be padded from the border, tuple[int, int] + :param modifier: a modifier to calculate [add/subtract]Quarters(), [add/subtract]Weeks() + :param mult: +/- selector + """ + stress = self.context.stress + timezones = timezones_range(stress) + + for year in years_range(stress=stress, padding=years_padding): + with Given(f"I choose datetimes in {year}"): + datetimes = select_dates_in_year(year=year, stress=stress) + + with When("I check each of the datetimes"): + for dt in datetimes: + for tz in timezones: + for incr in test_range: + with Example(f"{dt} {tz}"): + with By("converting datetime to string"): + dt_str = dt.strftime("%Y-%m-%d %H:%M:%S") + with And("computing the expected result using pytz"): + dt = eval(f"dt + rd.relativedelta({py_key}={mult*incr*modifier})") + expected = f"{dt.strftime('%Y-%m-%d %H:%M:%S')}" + with And("making a query string for ClickHouse"): + query = f"SELECT {clh_func}(toDateTime64('{dt_str}', 0, '{tz}'), {incr})" + with Then("I execute query"): + exec_query(request=query, expected=f"{expected}") + + +@TestScenario +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_addYears("1.0") +) +def add_years(self): + """Check the addYears function with DateTime64 extended range.""" + add_subtract_functions(clh_func="addYears", py_key="years", test_range=(0, 1), years_padding=(0, 1)) + + +@TestScenario +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_subtractYears("1.0") +) +def subtract_years(self): + """Check the subtractYears function with DateTime64 extended range.""" + add_subtract_functions(clh_func="subtractYears", py_key="years", test_range=(0, 1), years_padding=(1, 0), mult=-1) + + +@TestScenario +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_addQuarters("1.0") +) +def add_quarters(self): + """Check the addQuarters function with DateTime64 extended range.""" + add_subtract_functions(clh_func="addQuarters", py_key="months", test_range=range(1, 5), years_padding=(0, 1), modifier=3) + + +@TestScenario +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_subtractQuarters("1.0") +) +def subtract_quarters(self): + """Check the subtractQuarters function with DateTime64 extended range.""" + add_subtract_functions(clh_func="subtractQuarters", py_key="months", test_range=range(1, 5), years_padding=(1, 0), modifier=3, mult=-1) + + +@TestScenario +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_addMonths("1.0") +) +def add_months(self): + """Check the addMonths function with DateTime64 extended range.""" + add_subtract_functions(clh_func="addMonths", py_key="months", test_range=range(1, 13), years_padding=(0, 1)) + + +@TestScenario +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_subtractMonths("1.0") +) +def subtract_months(self): + """Check the subtractMonths function with DateTime64 extended range.""" + add_subtract_functions(clh_func="subtractMonths", py_key="months", test_range=range(1, 13), years_padding=(1, 0), mult=-1) + + +@TestScenario +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_addWeeks("1.0") +) +def add_weeks(self): + """Check the addWeeks function with DateTime64 extended range.""" + add_subtract_functions(clh_func="addWeeks", py_key="days", test_range=range(6), years_padding=(0, 1), modifier=7) + + +@TestScenario +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_subtractWeeks("1.0") +) +def subtract_weeks(self): + """Check the subtractWeeks function with DateTime64 extended range.""" + add_subtract_functions(clh_func="subtractWeeks", py_key="days", test_range=range(6), years_padding=(1, 0), modifier=7, mult=-1) + + + +@TestScenario +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_addDays("1.0") +) +def add_days(self): + """Check the addDays function work with DateTime64 extended range""" + add_subtract_functions(clh_func="addDays", py_key="days", test_range=range(50)) + + +@TestScenario +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_subtractDays("1.0") +) +def subtract_days(self): + """Check the subtractDays function work with DateTime64 extended range""" + add_subtract_functions(clh_func="subtractDays", py_key="days", test_range=range(50), mult=-1) + + +@TestScenario +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_addHours("1.0") +) +def add_hours(self): + """Check the addHours function work with DateTime64 extended range""" + add_subtract_functions(clh_func="addHours", py_key="hours", test_range=range(25)) + + +@TestScenario +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_subtractHours("1.0") +) +def subtract_hours(self): + """Check the subtractHours function work with DateTime64 extended range""" + add_subtract_functions(clh_func="subtractHours", py_key="hours", test_range=range(25), mult=-1) + + +@TestScenario +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_addMinutes("1.0") +) +def add_minutes(self): + """Check the addMinutes function work with DateTime64 extended range""" + add_subtract_functions(clh_func="addMinutes", py_key="minutes", test_range=range(60)) + + +@TestScenario +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_subtractMinutes("1.0") +) +def subtract_minutes(self): + """Check the subtractMinutes function work with DateTime64 extended range""" + add_subtract_functions(clh_func="subtractMinutes", py_key="minutes", test_range=range(60), mult=-1) + + +@TestScenario +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_addSeconds("1.0") +) +def add_seconds(self): + """Check the addSeconds function work with DateTime64 extended range""" + add_subtract_functions(clh_func="addSeconds", py_key="seconds", test_range=range(60)) + + +@TestScenario +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_subtractSeconds("1.0") +) +def subtract_seconds(self): + """Check the subtractSeconds function work with DateTime64 extended range""" + add_subtract_functions(clh_func="subtractSeconds", py_key="seconds", test_range=range(60), mult=-1) + + +def date_diff_helper(dt1, dt2: datetime.datetime, unit: str): + """Helper for computing dateDiff expected result using Python. + """ + delta = dt2 - dt1 + if unit == "second": + return delta.total_seconds() + elif unit == "minute": + return delta.total_seconds() // 60 + elif unit == "hour": + return delta.total_seconds() // 3600 + elif unit == "day": + return delta.total_seconds() // 86400 + elif unit == "week": + return delta.total_seconds() // 604800 + elif unit == "month": + return (dt2.year - dt1.year) * 12 + (dt2.month - dt1.month) + elif unit == "quarter": + return ((dt2.year - dt1.year) * 12 + (dt2.month - dt1.month)) // 3 + elif unit == "year": + return dt2.year - dt1.year + + +@TestScenario +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_dateDiff("1.0") +) +def date_diff(self): + """Check how dateDiff works with DateTime64 extended range. + """ + stress = self.context.stress + compare_units = ("second", "minute", "hour", "day", "week", "month", "quarter", "year") + timezones = timezones_range(stress=stress) + + with Background("I select a set of datetimes to be compared"): + datetimes = [] + for year in years_range(stress=stress): + datetimes += list(select_dates_in_year(year=year, stress=stress)) + + for dt_1, dt_2 in itertools.product(datetimes, datetimes): + for tz in timezones: + dt1_str = dt_1.strftime("%Y-%m-%d %H:%M:%S") + dt2_str = dt_2.strftime("%Y-%m-%d %H:%M:%S") + dt1 = pytz.timezone(tz).localize(dt_1) + dt2 = pytz.timezone(tz).localize(dt_2) + + for unit in compare_units: + with Example(f"{unit}: {dt1_str} {dt2_str}, {tz}"): + with When("I compute expected result with Pythons"): + expected = date_diff_helper(dt1=dt1, dt2=dt2, unit=unit) + with Then(f"I check dateDiff {dt1_str} {dt2_str} in {unit}"): + query = f"SELECT dateDiff('{unit}', toDateTime64('{dt1_str}', 0, '{tz}'), toDateTime64('{dt2_str}', 0, '{tz}'))" + exec_query(request=query, expected=expected) + + +@TestScenario +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_formatDateTime("1.0") +) +def format_date_time(self): + """Test formatDateTime() when DateTime64 is out of normal range. + This function formats DateTime according to a given Format string. + """ + stress = self.context.stress + timezones = timezones_range(stress) + + modes = ('C', 'd', 'D', 'e', 'F', 'G', 'g', 'H', 'I', 'j', 'm', 'M', 'n', + 'p', 'R', 'S', 't', 'T', 'u', 'V', 'w', 'y', 'Y', '%') + + for year in years_range(stress=stress): + with Given(f"I choose datetimes in {year}"): + datetimes = select_dates_in_year(year=year, stress=stress) + + with When("I format each of the datetimes in every possible way"): + for dt in datetimes: + for tz in timezones: + for mode in modes: + with Example(f"{dt} {tz}, format '%{mode}"): + with By("converting datetime to string"): + dt_str = dt.strftime("%Y-%m-%d %H:%M:%S") + with And("computing the expected result using python"): + expected = f"{dt.strftime(f'%{mode}')}" + with And("making a query string for ClickHouse"): + query = f"SELECT formatDateTime(toDateTime64('{dt_str}', 0, '{tz}'), '%{mode}')" + with Then("I execute formatDateTime() query"): + exec_query(request=query, expected=f"{expected}") + + +def time_slots_get_expected(dt: datetime.datetime, duration, size=1800): + """Helper to compute expected array for timeSlots(). + """ + zero_time = datetime.datetime(1970, 1, 1, 0, 0, 0) + + result = [(zero_time + datetime.timedelta(seconds=((dt - zero_time).total_seconds() // size * size))).strftime("%Y-%m-%d %H:%M:%S")] + + s = 1 + while s <= duration: + delta = dt - zero_time + datetime.timedelta(seconds=s) + seconds_rounded = delta.total_seconds() // size * size + r = zero_time + datetime.timedelta(seconds=seconds_rounded) + r_str = r.strftime("%Y-%m-%d %H:%M:%S") + if r_str not in result: + result.append(r_str) + s += size + else: + s += 1 + return result + + +@TestScenario +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions_timeSlots("1.0") +) +def time_slots(self): + """Check the timeSlots function with DateTime64 extended range. + syntax: timeSlots(StartTime, Duration _seconds_ [, Size _seconds_]) + """ + stress = self.context.stress + + for year in years_range(stress=stress): + with Given(f"I choose datetimes in {year}"): + datetimes = select_dates_in_year(year=year, stress=stress) + with When("I check each of the datetimes"): + for dt in datetimes: + for duration in range(1, 100, 9): + for size in range(1, 50, 3): + with Example(f"{dt}, dur={duration}, size={size}"): + with By("getting an expected array using python"): + expected = time_slots_get_expected(dt=dt, duration=duration, size=size) + with And("forming a ClickHouse query"): + dt_str = dt.strftime("%Y-%m-%d %H:%M:%S") + query = f"SELECT timeSlots(toDateTime64('{dt_str}', 0, 'UTC'), toUInt32({duration}), {size})" + with Then("I execute query"): + try: + assert eval(self.context.node.query(query).output) == expected, error() + except SyntaxError: + assert False + + +@TestFeature +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_DatesAndTimesFunctions("1.0") +) +def date_time_funcs(self, node="clickhouse1"): + """Check the basic operations with DateTime64 + """ + self.context.node = self.context.cluster.node(node) + + for scenario in loads(current_module(), Scenario): + Scenario(run=scenario, flags=TE) \ No newline at end of file diff --git a/tests/testflows/datetime64_extended_range/tests/generic.py b/tests/testflows/datetime64_extended_range/tests/generic.py new file mode 100644 index 00000000000..7626859810c --- /dev/null +++ b/tests/testflows/datetime64_extended_range/tests/generic.py @@ -0,0 +1,177 @@ +from testflows.core import * + +from datetime64_extended_range.requirements.requirements import * +from datetime64_extended_range.common import * +from datetime64_extended_range.tests.common import * + +import pytz +import datetime +import itertools + +@TestScenario +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_NormalRange_Start("1.0"), +) +def normal_range_start(self): + """Check DateTime64 can accept a dates around the start of the normal range that begins at 1970-01-01 00:00:00.000. + """ + with When("I do incrementing time sweep", description="check different time points in the first 24 hours at given date"): + walk_datetime_in_incrementing_steps(date="1970-01-01", precision=3, hrs_range=(0, 24)) + + +@TestScenario +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_NormalRange_End("1.0") +) +def normal_range_end(self): + """Check DateTime64 can accept a dates around the end of the normal range that ends at 2105-12-31 23:59:59.99999. + """ + with When("I do decrementing time sweep", + description="check different time points in the last 24 hours at given date"): + walk_datetime_in_decrementing_steps(date="2105-12-31", precision=3, hrs_range=(23, 0)) + + +@TestScenario +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_Start("1.0") +) +def extended_range_start(self): + """Check DateTime64 supports dates around the beginning of the extended range that begins at 1698-01-01 00:00:00.000000. + """ + with When("I do incrementing time sweep", + description="check different time points in the first 24 hours at given date"): + walk_datetime_in_incrementing_steps(date="1698-01-01", precision=5, hrs_range=(0, 24)) + + +@TestScenario +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_End("1.0") +) +def extended_range_end(self, precision=3): + """Check DateTime64 supports dates around the beginning of the extended range that ends at 2377-12-31T23:59:59.999999. + """ + with When("I do decrementing time sweep", + description="check different time points in the last 24 hours at given date"): + walk_datetime_in_decrementing_steps(date="2377-12-31", precision=5, hrs_range=(23, 0)) + + +@TestOutline(Scenario) +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_NormalRange_Start_BeforeEpochForTimeZone("1.0") +) +def timezone_local_below_normal_range(self): + """Check how UTC normal range time value treated + when current timezone time value is out of normal range. + """ + with When("I do incrementing time sweep", + description="check different time points when UTC datetime fits normal range but below it for local datetime"): + walk_datetime_in_incrementing_steps(date="1969-12-31", hrs_range=(17, 24), timezone='America/Phoenix') + + +@TestOutline(Scenario) +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_NormalRange_End_AfterEpochForTimeZone("1.0") +) +def timezone_local_above_normal_range(self): + """Check how UTC normal range time value treated + when current timezone time value is out of normal range. + """ + with When("I do decrementing time sweep", + description="check different time points when UTC datetime fits normal range but above it for local datetime"): + walk_datetime_in_decrementing_steps(date="2106-01-01", hrs_range=(6, 0), timezone='Asia/Novosibirsk') + + +@TestOutline(Scenario) +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_Start_BeforeEpochForTimeZone("1.0") +) +def timezone_local_below_extended_range(self): + """Check how UTC normal range time value treated + when current timezone time value is out of extended range. + """ + with When("I do incrementing time sweep", + description="check different time points when UTC datetime fits normal range but below it for local datetime"): + walk_datetime_in_incrementing_steps(date="1697-12-12", hrs_range=(17, 24), timezone='America/Phoenix') + + +@TestOutline(Scenario) +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_End_AfterEpochForTimeZone("1.0") +) +def timezone_local_above_extended_range(self): + """Check how UTC normal range time value treated + when current timezone time value is out of normal range. + """ + with When("I do decrementing time sweep", + description="check different time points when UTC datetime fits normal range but above it for local datetime"): + walk_datetime_in_decrementing_steps(date="2378-01-01", hrs_range=(6, 0), timezone='Asia/Novosibirsk') + + +@TestScenario +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_Comparison("1.0") +) +def comparison_check(self): + """Check how comparison works with DateTime64 extended range. + """ + stress = self.context.stress + comparators = (">", "<", "==", "<=", ">=", "!=") + timezones = timezones_range(stress=stress) + datetimes = [] + + for year in years_range(stress=stress): + datetimes += list(select_dates_in_year(year=year, stress=stress)) + + for dt_1, dt_2 in itertools.product(datetimes, datetimes): + for tz1, tz2 in itertools.product(timezones, timezones): + dt1_str = dt_1.strftime("%Y-%m-%d %H:%M:%S") + dt2_str = dt_2.strftime("%Y-%m-%d %H:%M:%S") + dt1 = pytz.timezone(tz1).localize(dt_1) + dt2 = pytz.timezone(tz2).localize(dt_2) + + with Example(f"{dt1_str} {tz1}, {dt2_str} {tz2}"): + for c in comparators: + expr = f"dt1 {c} dt2" + expected = str(int(eval(expr))) + with When(f"I check {dt1_str} {c} {dt2_str}"): + query = f"SELECT toDateTime64('{dt1_str}', 0, '{tz1}') {c} toDateTime64('{dt2_str}', 0, '{tz2}')" + exec_query(request=query, expected=expected) + + +@TestScenario +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_TimeZones("1.0") +) +def timezones_support(self): + """Check how timezones work with DateTime64 extended range. + """ + stress = self.context.stress + timezones = timezones_range(stress=stress) + + for year in years_range(stress): + with Given("I select datetimes in a year"): + datetimes = select_dates_in_year(year=year, stress=stress) + + for dt in datetimes: + for tz in timezones: + with Example(f"{dt} {tz}"): + with By("computing expected output using python"): + dt_str = dt.strftime("%Y-%m-%d %H:%M:%S") + with And("forming a toTimeZone ClickHouse query"): + query = f"SELECT toDateTime64('{dt_str}', 0, '{tz}')" + with Then(f"I execute query", flags=TE): + exec_query(request=query, expected=f"{dt_str}") + + + + + + +@TestFeature +def generic(self, node="clickhouse1"): + """Check the basic operations with DateTime64 + """ + self.context.node = self.context.cluster.node(node) + + for scenario in loads(current_module(), Scenario, Suite): + Scenario(run=scenario, flags=TE) diff --git a/tests/testflows/datetime64_extended_range/tests/non_existent_time.py b/tests/testflows/datetime64_extended_range/tests/non_existent_time.py new file mode 100644 index 00000000000..5f8f740480b --- /dev/null +++ b/tests/testflows/datetime64_extended_range/tests/non_existent_time.py @@ -0,0 +1,164 @@ +from testflows.core import * +import datetime + +from datetime64_extended_range.requirements.requirements import * +from datetime64_extended_range.tests.common import * + + +@TestScenario +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_NonExistentTime_InvalidDate("1.0") +) +def invalid_date(self): + """Check how non-existent date is treated. + For example, check 31st day in month that only has 30 days. + """ + date_range = [1700, 1980, 2300] + + if self.context.stress: + date_range = range(1698, 2378) + + with Step("I check 31st day of a 30-day month"): + for year in date_range: + for month in (4, 6, 9, 11): + datetime = f"{year}-{str(month).zfill(2)}-31 12:23:34" + expected = f"{year}-{str(month + 1).zfill(2)}-01 12:23:34" + + with Example(f"{datetime}", description=f"expected {expected}", flags=TE): + select_check_datetime(datetime=datetime, expected=expected) + + +@TestOutline(Suite) +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_NonExistentTime_InvalidTime("1.0") +) +@Examples( + "datetime expected timezone", [ + ('2002-04-07 02:30:00', '2002-04-07 01:30:00', 'America/New_York'), + ('2020-03-29 02:30:00', '2020-03-29 01:30:00', 'Europe/Zurich'), + ('2017-03-26 02:30:00', '2017-03-26 01:30:00', 'Europe/Berlin') + ]) +def invalid_time(self, datetime, expected, timezone='UTC'): + """proper handling of invalid time for a timezone + when using DateTime64 extended range data type, for example, + 2:30am on 7th April 2002 never happened at all in the US/Eastern timezone, + """ + with When(f"I check non-existent datetime {datetime}"): + select_check_datetime(datetime=datetime, expected=expected, timezone=timezone) + + +@TestOutline(Scenario) +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_NonExistentTime_DaylightSavingTime("1.0"), + RQ_SRS_010_DateTime64_ExtendedRange_NonExistentTime_DaylightSavingTime_Disappeared("1.0") +) +@Examples( + "tz time_dates", [ + ('America/Denver', {'02:30:00': ('2018-03-11', '2020-03-08', '1980-04-27', '1942-02-09')}), + ('Europe/Zurich', {'02:30:00': ('2016-03-27', '2020-03-29', '1981-03-29'), '01:30:00': ('1942-05-04', )}) +]) +def dst_disappeared(self, tz, time_dates): + """Proper handling of switching DST, when an hour is being skipped. + Testing in 2 steps: first, try to make a DateTime64 with skipped time value. + Second, adding interval so that result is in the skipped time. + """ + for time, dates in time_dates.items(): + for date in dates: + with Given(f"forming a datetime"): + dt_str = f"{date} {time}" + dt = datetime.datetime.strptime(dt_str, "%Y-%m-%d %H:%M:%S") + with Step("Assignment test"): + with When("computing expected result"): + dt -= datetime.timedelta(hours=1) + expected = dt.strftime("%Y-%m-%d %H:%M:%S") + with Then(f"I check skipped hour"): + select_check_datetime(datetime=dt_str, expected=expected, timezone=tz) + with Step("Addition test"): + with When("computing expected result"): + dt += datetime.timedelta(hours=2) + expected = dt.strftime("%Y-%m-%d %H:%M:%S") + with Then(f"I check skipped hour"): + query = f"SELECT addHours(toDateTime64('{dt_str}', 0, '{tz}'), 1)" + exec_query(request=query, expected=f"{expected}") + + +@TestOutline(Scenario) +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_NonExistentTime_LeapSeconds("1.0") +) +@Examples( + "datet years", [ + ("06-30 23:59:55", [1972, 1981, 1982, 1983, 1985, 1992, 1993, 1994, 1997, 2012, 2015]), + ("12-31 23:59:55", [1972, 1973, 1974, 1975, 1976, 1977, 1978, 1979, 1987, 1989, 1990, 1995, 1998, 2005, 2008, 2016]) +]) +def leap_seconds(self, datet, years): + """Test proper handling of leap seconds. Read more: https://de.wikipedia.org/wiki/Schaltsekunde + Being checked by selecting a timestamp prior to leap second and adding seconds so that the result is after it. + """ + for year in years: + with Example(f"{datet}, {year}"): + with By("forming an expected result using python"): + dt_str = f"{year}-{datet}" + dt = datetime.datetime.strptime(dt_str, '%Y-%m-%d %H:%M:%S') + dt += datetime.timedelta(seconds=9) + expected = dt.strftime("%Y-%m-%d %H:%M:%S") + with And(f"forming a query"): + query = f"SELECT addSeconds(toDateTime64('{dt_str}', 0, 'UTC'), 10)" + with Then("executing query"): + exec_query(request=query, expected=f"{expected}") + + +@TestScenario +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_NonExistentTime_DaylightSavingTime("1.0"), + RQ_SRS_010_DateTime64_ExtendedRange_NonExistentTime_TimeZoneSwitch("1.0") +) +def dst_time_zone_switch(self): + """Check how ClickHouse supports handling of invalid time when using DateTime64 extended range data type + when the invalid time is caused when countries switch timezone definitions with no daylight savings time switch. + """ + stress = self.context.stress + timezones = timezones_range(stress) + utc = pytz.timezone("UTC") + + for timezone in timezones: + if timezone == 'UTC': + continue + with Example(f"{timezone}"): + tz = pytz.timezone(timezone) + transition_times = tz._utc_transition_times[1:] + transition_info = tz._transition_info[1:] + + for i in range(len(transition_times)-1, 0, -1): + if transition_times[i] > datetime.datetime.now(): + continue + with Step(f"{transition_times[i]}"): + with By("localize python datetime"): + dt = transition_times[i] + dt0 = dt - datetime.timedelta(hours=4) + dt0 = utc.localize(dt0).astimezone(tz).replace(tzinfo=None) + with And("compute expected result using Pytz"): + seconds_shift = transition_info[i][0] - transition_info[i-1][0] + dt1 = dt0 + datetime.timedelta(hours=8) + seconds_shift + dt0_str = dt0.strftime("%Y-%m-%d %H:%M:%S") + dt1_str = dt1.strftime("%Y-%m-%d %H:%M:%S") + with And("forming a ClickHouse query"): + query = f"SELECT addHours(toDateTime64('{dt0_str}', 0, '{timezone}'), 8)" + with Then("executing the query"): + exec_query(request=query, expected=f"{dt1_str}") + + + + +@TestFeature +@Name("non existent time") +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_NonExistentTime("1.0") +) +def feature(self, node="clickhouse1"): + """Check how ClickHouse treats non-existent time in DateTime64 data type. + """ + self.context.node = self.context.cluster.node(node) + + for scenario in loads(current_module(), Scenario, Suite): + Scenario(run=scenario, flags=TE) diff --git a/tests/testflows/datetime64_extended_range/tests/reference_times.py b/tests/testflows/datetime64_extended_range/tests/reference_times.py new file mode 100644 index 00000000000..4d4762cc756 --- /dev/null +++ b/tests/testflows/datetime64_extended_range/tests/reference_times.py @@ -0,0 +1,38 @@ +import pytz +from datetime import datetime + +from testflows.core import * +from datetime64_extended_range.common import * +from datetime64_extended_range.tests.common import select_check_datetime +from datetime64_extended_range.requirements.requirements import * +from datetime64_extended_range.tests.common import * + + +@TestSuite +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_SpecificTimestamps("1.0") +) +def reference_times(self, node="clickhouse1"): + """Check how ClickHouse converts a set of particular timestamps + to DateTime64 for all timezones and compare the result to pytz. + """ + self.context.node = self.context.cluster.node(node) + + timestamps = [9961200, 73476000, 325666800, 354675600, 370400400, 386125200, 388566010, 401850000, 417574811, + 496803600, 528253200, 624423614, 636516015, 671011200, 717555600, 752047218, 859683600, 922582800, + 1018173600, 1035705600, 1143334800, 1162105223, 1174784400, 1194156000, 1206838823, 1224982823, + 1236495624, 1319936400, 1319936424, 1425798025, 1459040400, 1509872400, 2090451627, 2140668000] + + query = "" + + for tz in pytz.all_timezones: + timezone = pytz.timezone(tz) + query += f"select '{tz}', arrayJoin(arrayFilter(x -> x.2 <> x.3, arrayMap(x -> tuple(x.1, x.2, toString(toDateTime64(x.1, 0, '{tz}'))), [" + need_comma = 0 + for timestamp in timestamps: + for reference_timestamp in [timestamp - 1, timestamp, timestamp + 1]: + query += f"{',' if need_comma else ''}tuple({reference_timestamp},'{datetime.datetime.fromtimestamp(reference_timestamp, timezone).strftime('%Y-%m-%d %H:%M:%S')}')" + need_comma = 1 + query += "] ) ) );" + + exec_query(request=query, expected="") diff --git a/tests/testflows/datetime64_extended_range/tests/type_conversion.py b/tests/testflows/datetime64_extended_range/tests/type_conversion.py new file mode 100644 index 00000000000..c6758b2d6c0 --- /dev/null +++ b/tests/testflows/datetime64_extended_range/tests/type_conversion.py @@ -0,0 +1,479 @@ +import time +import pytz +import decimal +import itertools +import numpy as np +from dateutil.tz import tzlocal +from datetime import datetime, timedelta +import dateutil.relativedelta as rd +from testflows.core import * + +from datetime64_extended_range.requirements.requirements import * +from datetime64_extended_range.common import * +from datetime64_extended_range.tests.common import * + + +@TestOutline(Scenario) +@Examples("cast", [ + (False, Requirements(RQ_SRS_010_DateTime64_ExtendedRange_TypeConversionFunctions_toInt_8_16_32_64_128_256_("1.0"))), + (True, Requirements(RQ_SRS_010_DateTime64_ExtendedRange_TypeConversionFunctions_CAST_x_T_("1.0"))) +]) +def to_int_8_16_32_64_128_256(self, cast): + """Check the toInt(8|16|32|64|128|256) functions with DateTime64 extended range + """ + stress = self.context.stress + timezones = timezones_range(stress) + + for year in years_range(stress): + with Given("I select datetimes in a year"): + datetimes = select_dates_in_year(year=year, stress=stress) + + for d in datetimes: + for tz in timezones: + dt = pytz.timezone(tz).localize(d) + for int_type in (8, 16, 32, 64, 128, 256): + with Example(f"{dt} {tz}, int{int_type}"): + with By("converting datetime to string"): + dt_str = dt.strftime("%Y-%m-%d %H:%M:%S") + with And("computing the expected result using python"): + py_res = int(time.mktime(dt.timetuple())) + expected = f"{py_res}" + if not (int_type == 128 or int_type == 256): + """ALL dates fit into int128 and int256, so no need to check""" + np_res = exec(f"np.int{int_type}({py_res})") + else: + np_res = py_res + if np_res == py_res: + with Given(f"{py_res} fits int{int_type}"): + with When(f"making a query string for ClickHouse if py_res fits int{int_type}"): + if cast: + query = f"SELECT cast(toDateTime64('{dt_str}', 0, '{tz}'), 'Int{int_type}')" + else: + query = f"SELECT toInt{int_type}(toDateTime64('{dt_str}', 0, '{tz}'))" + with Then(f"I execute toInt{int_type}() query"): + exec_query(request=query, expected=f"{expected}") + + +@TestOutline(Scenario) +@Examples("cast", [ + (False, Requirements(RQ_SRS_010_DateTime64_ExtendedRange_TypeConversionFunctions_toUInt_8_16_32_64_256_("1.0"))), + (True, Requirements(RQ_SRS_010_DateTime64_ExtendedRange_TypeConversionFunctions_CAST_x_T_("1.0"))) +]) +def to_uint_8_16_32_64_256(self, cast): + """Check the toUInt(8|16|32|64|256) functions with DateTime64 extended range + """ + stress = self.context.stress + timezones = timezones_range(stress) + + for year in years_range(stress): + with Given("I select datetimes in a year"): + datetimes = select_dates_in_year(year=year, stress=stress) + + for d in datetimes: + for tz in timezones: + dt = pytz.timezone(tz).localize(d) + for int_type in (8, 16, 32, 64, 256): + with Example(f"{dt} {tz}, int{int_type}"): + with By("converting datetime to string"): + dt_str = dt.strftime("%Y-%m-%d %H:%M:%S") + with And("computing the expected result using python"): + py_res = int(time.mktime(dt.timetuple())) + expected = f"{py_res}" + if int_type != 256: + """ALL dates fit into uint256, so no need to check""" + np_res = exec(f"np.uint{int_type}({py_res})") + else: + np_res = py_res + if np_res == py_res: + with Given(f"{py_res} fits int{int_type}"): + with When(f"making a query string for ClickHouse if py_res fits int{int_type}"): + if cast: + query = f"SELECT cast(toDateTime64('{dt_str}', 0, '{tz}'), 'UInt{int_type}')" + else: + query = f"SELECT toUInt{int_type}(toDateTime64('{dt_str}', 0, '{tz}'))" + with Then(f"I execute toInt{int_type}() query"): + exec_query(request=query, expected=f"{expected}") + + +@TestOutline(Scenario) +@Examples("cast", [ + (False, Requirements(RQ_SRS_010_DateTime64_ExtendedRange_TypeConversionFunctions_toFloat_32_64_("1.0"))), + (True, Requirements(RQ_SRS_010_DateTime64_ExtendedRange_TypeConversionFunctions_CAST_x_T_("1.0"))) +]) +def to_float_32_64(self, cast): + """Check the toFloat(32|64) functions with DateTime64 extended range + """ + stress = self.context.stress + timezones = timezones_range(stress) + + for year in years_range(stress): + with Given("I select datetimes in a year"): + datetimes = select_dates_in_year(year=year, stress=stress) + + for d in datetimes: + for tz in timezones: + dt = pytz.timezone(tz).localize(d) + for float_type in (32, 64): + with Example(f"{dt} {tz}, int{float_type}"): + with By("converting datetime to string"): + dt_str = dt.strftime("%Y-%m-%d %H:%M:%S") + with And("computing the expected result using python"): + py_res = int(time.mktime(dt.timetuple())) + expected = f"{py_res}" + np_res = exec(f"np.float{float_type}({py_res})") + if np_res == py_res: + with When(f"making a query string for ClickHouse"): + if cast: + query = f"SELECT cast(toDateTime64('{dt_str}', 0, '{tz}'), 'Float{float_type}')" + else: + query = f"SELECT toFloat{float_type}(toDateTime64('{dt_str}', 0, '{tz}'))" + with Then(f"I execute toFloat{float_type}() query"): + exec_query(request=query, expected=f"{expected}") + + +@TestScenario +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_TypeConversionFunctions_toDateTime64_FromString_MissingTime("1.0") +) +def to_datetime64_from_string_missing_time(self): + """Check the toDateTime64() with DateTime64 extended range conversion when string is missing the time part. + """ + stress = self.context.stress + timezones = timezones_range(stress) + + for year in years_range(stress): + with Given("I select datetimes in a year"): + datetimes = select_dates_in_year(year=year, stress=stress) + + for dt in datetimes: + for tz in timezones: + with Example(f"{dt} {tz}"): + with By("converting datetime to string"): + dt_str = dt.strftime("%Y-%m-%d") + with And("figure out expected result in python"): + expected = f"{dt.strftime('%Y-%m-%d')} 00:00:00" + with When(f"making a query string for ClickHouse"): + query = f"SELECT toDateTime64('{dt_str}', 0, '{tz}')" + with Then(f"I execute toDateTime64() query"): + exec_query(request=query, expected=f"{expected}") + + +@TestScenario +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_TypeConversionFunctions_toDateTime64("1.0") +) +def to_datetime64(self): + """Check the toDateTime64() conversion with DateTime64. This is supposed to work in normal range ONLY. + """ + stress = self.context.stress + timezones = timezones_range(stress) + + for year in years_range(stress): + with Given("I select datetimes in a year"): + datetimes = select_dates_in_year(year=year, stress=stress) + + for dt in datetimes: + for tz in timezones: + with By("converting datetime to string"): + dt_str = dt.strftime("%Y-%m-%d %H:%M:%S") + with And(f"making a query string for ClickHouse"): + query = f"SELECT toDateTime64('{dt_str}', 0, '{tz}')" + with When("figure out expected result in python"): + expected = f"{dt.strftime('%Y-%m-%d %H:%M:%S')}" + with Then(f"I execute toDateTime64() query"): + exec_query(request=query, expected=f"{expected}") + + +@TestOutline(Scenario) +@Examples("cast", [ + (False, Requirements(RQ_SRS_010_DateTime64_ExtendedRange_TypeConversionFunctions_toDate("1.0"))), + (True, Requirements(RQ_SRS_010_DateTime64_ExtendedRange_TypeConversionFunctions_CAST_x_T_("1.0"))) +]) +def to_date(self, cast): + """Check the toDate() conversion with DateTime64. This is supposed to work in normal range ONLY. + """ + stress = self.context.stress + timezones = timezones_range(stress) + + for year in years_range(stress): + with Given("I select datetimes in a year"): + datetimes = select_dates_in_year(year=year, stress=stress) + + for dt in datetimes: + for tz in timezones: + with Example(f"{dt} {tz}"): + expected = None # by default - not checked, checking the exitcode + with By("converting datetime to string"): + dt_str = dt.strftime("%Y-%m-%d %H:%M:%S") + + if in_normal_range(dt): + with And("DateTime64 fits normal range, change its value"): + expected = f"{dt.strftime('%Y-%m-%d')}" # being checked in case DateTime64 fits normal range + + with Given(f"I make a query string for ClickHouse"): + if cast: + query = f"SELECT CAST(toDateTime64('{dt_str}', 0, '{tz}'), 'Date')" + else: + query = f"SELECT toDate(toDateTime64('{dt_str}', 0, '{tz}'))" + + with Then(f"I execute toDate() query and check return/exitcode"): + exec_query(request=query, expected=expected, exitcode=0) + + +@TestOutline(Scenario) +@Examples("cast", [ + (False, Requirements(RQ_SRS_010_DateTime64_ExtendedRange_TypeConversionFunctions_toDateTime("1.0"))), + (True, Requirements(RQ_SRS_010_DateTime64_ExtendedRange_TypeConversionFunctions_CAST_x_T_("1.0"))) +]) +def to_datetime(self, cast): + """Check the toDateTime() conversion with DateTime64. This is supposed to work in normal range ONLY. + """ + stress = self.context.stress + timezones = timezones_range(stress) + + for year in years_range(stress): + with Given("I select datetimes in a year"): + datetimes = select_dates_in_year(year=year, stress=stress) + + for dt in datetimes: + for tz in timezones: + with By("converting datetime to string"): + dt_str = dt.strftime("%Y-%m-%d %H:%M:%S") + with And(f"making a query string for ClickHouse"): + if cast: + query = f"SELECT CAST(toDateTime64('{dt_str}', 0, '{tz}'), 'DateTime')" + with When("figure out expected result in python"): + dt_local = pytz.timezone(tz).localize(dt) + dt_transformed = dt_local.astimezone(tzlocal()) + expected = f"{dt_transformed.strftime('%Y-%m-%d %H:%M:%S')}" + else: + query = f"SELECT toDateTime(toDateTime64('{dt_str}', 0, '{tz}'))" + with When("figure out expected result in python"): + expected = f"{dt.strftime('%Y-%m-%d %H:%M:%S')}" + + if not in_normal_range(dt): + with When(f"I execute toDateTime() query out of normal range"): + exec_query(request=query, exitcode=0) + else: + with When(f"I execute toDateTime() query"): + exec_query(request=query, expected=f"{expected}") + + +@TestOutline(Scenario) +@Examples("cast", [ + (False, Requirements(RQ_SRS_010_DateTime64_ExtendedRange_TypeConversionFunctions_toString("1.0"))), + (True, Requirements(RQ_SRS_010_DateTime64_ExtendedRange_TypeConversionFunctions_CAST_x_T_("1.0"))) +]) +def to_string(self, cast): + """Check the toString() with DateTime64 extended range. + """ + stress = self.context.stress + timezones = timezones_range(stress) + + for year in years_range(stress): + with Given("I select datetimes in a year"): + datetimes = select_dates_in_year(year=year, stress=stress) + + for dt in datetimes: + for tz in timezones: + with Example(f"{dt} {tz}"): + with By("converting datetime to string"): + dt_str = dt.strftime("%Y-%m-%d %H:%M:%S") + with When(f"making a query string for ClickHouse"): + if cast: + query = f"SELECT cast(toDateTime64('{dt_str}', 0, '{tz}'), 'String')" + else: + query = f"SELECT toString(toDateTime64('{dt_str}', 0, '{tz}'))" + with Then(f"I execute toDateTime64() query"): + exec_query(request=query, expected=f"{dt_str}") + + +def valid_decimal_range(bit_depth, S): + """A helper to find valid range for Decimal(32|64|128|256) with given scale (S)""" + return {32: -1 * 10 ** (9 - S), 64: -1 * 10 ** (18 - S), 128: -1 * 10 ** (38 - S), 256: -1 * 10 ** (76 - S)}[ + bit_depth] + + +@TestOutline(Scenario) +@Examples("cast", [ + (False, Requirements(RQ_SRS_010_DateTime64_ExtendedRange_TypeConversionFunctions_toDecimal_32_64_128_256_("1.0"))), + (True, Requirements(RQ_SRS_010_DateTime64_ExtendedRange_TypeConversionFunctions_CAST_x_T_("1.0"))) +]) +def to_decimal_32_64_128_256(self, cast): + """Check the toDecimal(32|64|128|256) functions with DateTime64 extended range. + Decimal32(S) - ( -1 * 10^(9 - S), 1 * 10^(9 - S) ) + Decimal64(S) - ( -1 * 10^(18 - S), 1 * 10^(18 - S) ) + Decimal128(S) - ( -1 * 10^(38 - S), 1 * 10^(38 - S) ) + Decimal256(S) - ( -1 * 10^(76 - S), 1 * 10^(76 - S) ) + """ + stress = self.context.stress + timezones = timezones_range(stress) + scales = {32: 9, 64: 18, 128: 38, 256: 76} + + for year in years_range(stress): + with Given("I select datetimes in a year"): + datetimes = select_dates_in_year(year=year, stress=stress) + + for d in datetimes: + for tz in timezones: + dt = pytz.timezone(tz).localize(d) + for decimal_type in (32, 64, 128, 256): + for scale in range(scales[decimal_type]): + with Example(f"{dt} {tz}, Decimal{decimal_type}({scale})"): + valid_range = valid_decimal_range(bit_depth=decimal_type, S=scale) + with By("computing the expected result using python"): + expected = decimal.Decimal(time.mktime(dt.timetuple())) + if -valid_range < expected < valid_range: + with And("converting datetime to string"): + dt_str = dt.strftime("%Y-%m-%d %H:%M:%S") + with When(f"making a query string for ClickHouse"): + if cast: + query = f"SELECT cast(toDateTime64('{dt_str}', 0, '{tz}'), 'Decimal({decimal_type}, {scale})')" + else: + query = f"SELECT toDecimal{decimal_type}(toDateTime64('{dt_str}', 0, '{tz}'))" + with Then(f"I execute toDecimal{decimal_type}() query"): + exec_query(request=query, expected=f"{expected}") + + +@TestOutline +def to_unix_timestamp64_milli_micro_nano(self, scale): + """Check the toUnixTimestamp64[Milli/Micro/Nano] functions with DateTime64 extended range. + :param scale: 3 for milli, 6 for micro, 9 for nano; int + """ + stress = self.context.stress + timezones = timezones_range(stress) + func = {3: 'Milli', 6: 'Micro', 9: 'Nano'} + + for year in years_range(stress): + with Given("I select datetimes in a year"): + datetimes = select_dates_in_year(year=year, stress=stress, microseconds=True) + + for d in datetimes: + for tz in timezones: + dt = pytz.timezone(tz).localize(d) + with Example(f"{dt} {tz}"): + with By("converting datetime to string"): + dt_str = dt.strftime("%Y-%m-%d %H:%M:%S.%f") + with And("converting DateTime to UTC"): + dt = dt.astimezone(pytz.timezone('UTC')) + with And("computing the expected result using python"): + expected = int(time.mktime(dt.timetuple()) * (10**scale)) + if expected >= 0: + expected += dt.microsecond * 10 ** (scale - 6) + else: + expected -= dt.microsecond * 10 ** (scale - 6) + with When(f"making a query string for ClickHouse"): + query = f"SELECT toUnixTimestamp64{func[scale]}(toDateTime64('{dt_str}', {scale}, '{tz}'))" + with Then(f"I execute toUnixTimestamp64{func[scale]}() query"): + exec_query(request=query, expected=f"{expected}") + + +@TestScenario +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_TypeConversionFunctions_toUnixTimestamp64Milli("1.0") +) +def to_unix_timestamp64_milli(self): + """Check the toUnixTimestamp64Milli functions with DateTime64 extended range. + """ + to_unix_timestamp64_milli_micro_nano(scale=3) + + +@TestScenario +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_TypeConversionFunctions_toUnixTimestamp64Micro("1.0") +) +def to_unix_timestamp64_micro(self): + """Check the toUnixTimestamp64Micro functions with DateTime64 extended range. + """ + to_unix_timestamp64_milli_micro_nano(scale=6) + + +@TestScenario +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_TypeConversionFunctions_toUnixTimestamp64Nano("1.0") +) +def to_unix_timestamp64_nano(self): + """Check the toUnixTimestamp64Nano functions with DateTime64 extended range. + """ + to_unix_timestamp64_milli_micro_nano(scale=9) + + +@TestOutline +def from_unix_timestamp64_milli_micro_nano(self, scale): + """Check the fromUnixTimestamp64[Milli/Micro/Nano] functions with DateTime64 extended range. + :param scale: 3 for milli, 6 for micro, 9 for nano; int + """ + stress = self.context.stress + timezones = timezones_range(stress) + func = {3: 'Milli', 6: 'Micro', 9: 'Nano'} + + for year in years_range(stress): + with Given("I select datetimes in a year"): + datetimes = select_dates_in_year(year=year, stress=stress, microseconds=True) + + for d in datetimes: + for tz in timezones: + dt = pytz.timezone(tz).localize(d) + with Example(f"{dt} {tz}"): + with By("converting datetime to string"): + d_str = d.strftime("%Y-%m-%d %H:%M:%S.%f") + d_str += "0" * (scale-3) + with And("converting DateTime to UTC"): + dt = dt.astimezone(pytz.timezone('UTC')) + with And("computing the expected result using python"): + ts = int(time.mktime(dt.timetuple()) * (10**scale)) + if ts >= 0: + ts += dt.microsecond * 10 ** (scale - 6) + else: + ts -= dt.microsecond * 10 ** (scale - 6) + with When(f"making a query string for ClickHouse"): + query = f"SELECT fromUnixTimestamp64{func[scale]}(CAST({ts}, 'Int64'), '{tz}')" + with Then(f"I execute fromUnixTimestamp64{func[scale]}() query"): + exec_query(request=query, expected=f"{d_str}") + + +@TestScenario +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_TypeConversionFunctions_fromUnixTimestamp64Milli("1.0") +) +def from_unix_timestamp64_milli(self): + """Check the fromUnixTimestamp64Milli functions with DateTime64 extended range. + """ + from_unix_timestamp64_milli_micro_nano(scale=3) + + +@TestScenario +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_TypeConversionFunctions_fromUnixTimestamp64Micro("1.0") +) +def from_unix_timestamp64_micro(self): + """Check the fromUnixTimestamp64Micro functions with DateTime64 extended range. + """ + from_unix_timestamp64_milli_micro_nano(scale=6) + + +@TestScenario +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_TypeConversionFunctions_fromUnixTimestamp64Nano("1.0") +) +def from_unix_timestamp64_nano(self): + """Check the fromUnixTimestamp64Nano functions with DateTime64 extended range. + """ + from_unix_timestamp64_milli_micro_nano(scale=9) + + + + + +@TestFeature +@Requirements( + RQ_SRS_010_DateTime64_ExtendedRange_TypeConversionFunctions("1.0") +) +def type_conversion(self, node="clickhouse1"): + """Check the type conversion operations with DateTime64. Cast can be set as Requirement thereby as the module + tests exactly what CAST does. + """ + self.context.node = self.context.cluster.node(node) + + for scenario in loads(current_module(), Scenario): + Scenario(run=scenario, flags=TE) diff --git a/tests/testflows/regression.py b/tests/testflows/regression.py index 0e9a821cae0..486e3a0a61e 100755 --- a/tests/testflows/regression.py +++ b/tests/testflows/regression.py @@ -18,6 +18,7 @@ def regression(self, local, clickhouse_binary_path, stress=None, parallel=None): Feature(test=load("ldap.regression", "regression"))(**args) Feature(test=load("rbac.regression", "regression"))(**args) Feature(test=load("aes_encryption.regression", "regression"))(**args) + Feature(test=load("datetime64_extended_range.regression", "regression"))(**args) if main(): regression()