From 69261b6a6c2d948cbccab740199ae3bef1131797 Mon Sep 17 00:00:00 2001 From: spol Date: Wed, 23 Sep 2026 21:57:36 +0300 Subject: [PATCH 1/9] Calculate milliseconds since epoch in snowflake.py Implement current milliseconds calculation and update return value. --- src/part1/snowflake.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/part1/snowflake.py b/src/part1/snowflake.py index d3abf050..58af1675 100644 --- a/src/part1/snowflake.py +++ b/src/part1/snowflake.py @@ -34,8 +34,9 @@ def read_current_millis(epoch_ms: int) -> int: The count of whole milliseconds between ``epoch_ms`` and now. May be negative if ``epoch_ms`` lies in the future. """ + current_millis = time.time_ns() // 1_000_000 # TODO: реализуйте функцию - return 0 + return (current_millis - epoch_ms) def decode_timestamp_ms(snowflake_id: int, epoch_ms: int = EPOCH_MS_DEFAULT) -> int: @@ -87,6 +88,18 @@ def generate_snowflake_id( node_id: int = NODE_ID_DEFAULT, epoch_ms: int = EPOCH_MS_DEFAULT, ) -> int | None: + + if node_id < 0 or node_id > NODE_ID_MAX: + print(f"Invalid node_id: {node_id}, node_id must be in [0, {NODE_ID_MAX}].") + return None + if sequence_id < 0 or sequence_id > SEQUENCE_MAX: + print(f"Invalid sequence_id: {sequence_id}, sequence_id must be in [0, {SEQUENCE_MAX}].") + return None + if epoch_ms < 0 or epoch_ms > TIMESTAMP_MS_MAX: + print(f"Invalid epoch_ms: {epoch_ms}, epoch_ms must be in [0, {TIMESTAMP_MS_MAX}].") + return None + + """Build and return a Snowflake identifier for the current millisecond. The function is stateless: the caller passes the per-millisecond sequence From cd453798cf889882deca6ab95ce01436d33a15a9 Mon Sep 17 00:00:00 2001 From: spol Date: Wed, 23 Sep 2026 22:03:14 +0300 Subject: [PATCH 2/9] Define constants for Snowflake ID generator Updated constants for Twitter Snowflake ID generator, including default epoch and bit widths. --- src/part1/constants.py | 34 ++++++++-------------------------- 1 file changed, 8 insertions(+), 26 deletions(-) diff --git a/src/part1/constants.py b/src/part1/constants.py index 9abfbba2..0c933fbf 100644 --- a/src/part1/constants.py +++ b/src/part1/constants.py @@ -1,38 +1,20 @@ -"""Bit layout and default epoch for the Twitter Snowflake ID generator. - -A Snowflake identifier is a 63-bit positive integer packed as follows, from -the most significant bit downwards: - - 1 bit unused sign bit, always zero - 41 bits milliseconds elapsed since a custom epoch - 10 bits node identifier - 12 bits per-millisecond sequence counter - -The shift and mask constants should be derived from the bit widths so that -changing a width keeps everything else consistent. -""" - from typing import Final - -# TODO: замените заглушки (0) на корректные значения, см. TASK.md. -# Все константы, зависящие от ёмкостей *_BITS, должны вычисляться из них. - # Twitter's original Snowflake epoch: 2010-11-04 01:42:54.657 UTC. -EPOCH_MS_DEFAULT: Final[int] = 0 +EPOCH_MS_DEFAULT: Final[int] = 1288834974657 # Node identifier used when the caller does not supply one. -NODE_ID_DEFAULT: Final[int] = 0 +NODE_ID_DEFAULT: Final[int] = 1 # Width of each field, in bits. -TIMESTAMP_BITS: Final[int] = 0 -NODE_ID_BITS: Final[int] = 0 -SEQUENCE_ID_BITS: Final[int] = 0 +TIMESTAMP_BITS: Final[int] = 41 +NODE_ID_BITS: Final[int] = 10 +SEQUENCE_ID_BITS: Final[int] = 12 # Largest value each field can hold. -TIMESTAMP_MS_MAX: Final[int] = 0 -NODE_ID_MAX: Final[int] = 0 -SEQUENCE_ID_MAX: Final[int] = 0 +TIMESTAMP_MS_MAX: Final[int] = 2**TIMESTAMP_BITS - 1 +NODE_ID_MAX: Final[int] = 2**NODE_ID_BITS - 1 +SEQUENCE_ID_MAX: Final[int] = 2**SEQUENCE_ID_BITS - 1 # Здесь можно добавить собственные вспомогательные константы # (например, сдвиги полей при сборке идентификатора). From 16f067120d781ad9bc7613748765db5f02ae3edb Mon Sep 17 00:00:00 2001 From: spol Date: Wed, 23 Sep 2026 23:03:44 +0300 Subject: [PATCH 3/9] Update snowflake.py --- src/part1/snowflake.py | 47 ++++++++++-------------------------------- 1 file changed, 11 insertions(+), 36 deletions(-) diff --git a/src/part1/snowflake.py b/src/part1/snowflake.py index 58af1675..799f9173 100644 --- a/src/part1/snowflake.py +++ b/src/part1/snowflake.py @@ -25,34 +25,14 @@ def read_current_millis(epoch_ms: int) -> int: - """Read the number of milliseconds elapsed since the custom epoch. - - Args: - epoch_ms: The custom epoch expressed as Unix milliseconds. - - Returns: - The count of whole milliseconds between ``epoch_ms`` and now. May be - negative if ``epoch_ms`` lies in the future. - """ - current_millis = time.time_ns() // 1_000_000 - # TODO: реализуйте функцию - return (current_millis - epoch_ms) + unix_epoch_time = time.time_ns() // 1_000_000_000 + return (unix_epoch_time - epoch_ms) def decode_timestamp_ms(snowflake_id: int, epoch_ms: int = EPOCH_MS_DEFAULT) -> int: - """Read the timestamp field out of a Snowflake identifier. - - Args: - snowflake_id: An identifier produced against the same epoch. - epoch_ms: The epoch the identifier was generated against. Defaults to - the original Twitter epoch (2010-11-04 01:42:54.657 UTC). - - Returns: - The absolute Unix time in milliseconds at which the identifier was - generated. - """ - # TODO: реализуйте функцию - return 0 + snowflake_binary = bin(snowflake_id)[2:] + snowflake_ms_binary = (snowflake_binary.zfill(63))[:41] + return (int(snowflake_ms_binary) + epoch_ms) def decode_node_id(snowflake_id: int) -> int: @@ -65,22 +45,17 @@ def decode_node_id(snowflake_id: int) -> int: The node identifier packed into ``snowflake_id``, in the range ``[0, NODE_ID_MAX]``. """ + snowflake_binary = bin(snowflake_id)[2:] + snowflake_node_id_binary = bin(snowflake_binary.zfill(63))[41:51]) # TODO: реализуйте функцию - return 0 + return int(snowflake_node_id_binary) def decode_sequence_id(snowflake_id: int) -> int: - """Read the sequence counter field out of a Snowflake identifier. - - Args: - snowflake_id: An identifier produced by :func:`generate_snowflake_id`. - - Returns: - The per-millisecond sequence counter packed into ``snowflake_id``, in - the range ``[0, SEQUENCE_ID_MAX]``. - """ + snowflake_binary = bin(snowflake_id)[2:] + snowflake_sequence_id_binary = bin(snowflake_binary.zfill(63))[51:]) # TODO: реализуйте функцию - return 0 + return int(snowflake_sequence_id_binary) def generate_snowflake_id( From aebb72d75d8939b0758672817c0e74f1c0ea222f Mon Sep 17 00:00:00 2001 From: spol Date: Fri, 25 Sep 2026 17:58:46 +0300 Subject: [PATCH 4/9] Refactor snowflake ID generation and decoding functions --- src/part1/snowflake.py | 74 +++++++++--------------------------------- 1 file changed, 16 insertions(+), 58 deletions(-) diff --git a/src/part1/snowflake.py b/src/part1/snowflake.py index 799f9173..de57e15e 100644 --- a/src/part1/snowflake.py +++ b/src/part1/snowflake.py @@ -25,78 +25,36 @@ def read_current_millis(epoch_ms: int) -> int: - unix_epoch_time = time.time_ns() // 1_000_000_000 + unix_epoch_time = time.time_ns() // 1_000_000 # get current time in milliseconds return (unix_epoch_time - epoch_ms) def decode_timestamp_ms(snowflake_id: int, epoch_ms: int = EPOCH_MS_DEFAULT) -> int: - snowflake_binary = bin(snowflake_id)[2:] - snowflake_ms_binary = (snowflake_binary.zfill(63))[:41] - return (int(snowflake_ms_binary) + epoch_ms) + return (snowflake_id >> (NODE_ID_BITS + SEQUENCE_ID_BITS)) + epoch_ms def decode_node_id(snowflake_id: int) -> int: - """Read the node identifier field out of a Snowflake identifier. + return (snowflake_id >> SEQUENCE_ID_BITS) & NODE_ID_MAX - Args: - snowflake_id: An identifier produced by :func:`generate_snowflake_id`. - Returns: - The node identifier packed into ``snowflake_id``, in the range - ``[0, NODE_ID_MAX]``. - """ - snowflake_binary = bin(snowflake_id)[2:] - snowflake_node_id_binary = bin(snowflake_binary.zfill(63))[41:51]) - # TODO: реализуйте функцию - return int(snowflake_node_id_binary) +def decode_sequence_id(snowflake_id: int) -> int: + return snowflake_id & SEQUENCE_ID_MAX +def generate_snowflake_id(sequence_id: int, node_id: int = NODE_ID_DEFAULT, epoch_ms: int = EPOCH_MS_DEFAULT) -> int | None: + timestamp_ms = read_current_millis(epoch_ms) -def decode_sequence_id(snowflake_id: int) -> int: - snowflake_binary = bin(snowflake_id)[2:] - snowflake_sequence_id_binary = bin(snowflake_binary.zfill(63))[51:]) - # TODO: реализуйте функцию - return int(snowflake_sequence_id_binary) - - -def generate_snowflake_id( - sequence_id: int, - node_id: int = NODE_ID_DEFAULT, - epoch_ms: int = EPOCH_MS_DEFAULT, -) -> int | None: - if node_id < 0 or node_id > NODE_ID_MAX: print(f"Invalid node_id: {node_id}, node_id must be in [0, {NODE_ID_MAX}].") return None - if sequence_id < 0 or sequence_id > SEQUENCE_MAX: - print(f"Invalid sequence_id: {sequence_id}, sequence_id must be in [0, {SEQUENCE_MAX}].") + if sequence_id < 0 or sequence_id > SEQUENCE_ID_MAX: + print(f"Invalid sequence_id: {sequence_id}, sequence_id must be in [0, {SEQUENCE_ID_MAX}].") return None - if epoch_ms < 0 or epoch_ms > TIMESTAMP_MS_MAX: - print(f"Invalid epoch_ms: {epoch_ms}, epoch_ms must be in [0, {TIMESTAMP_MS_MAX}].") + if timestamp_ms < 0 or timestamp_ms > TIMESTAMP_MS_MAX: + print("overflows") return None - - """Build and return a Snowflake identifier for the current millisecond. - - The function is stateless: the caller passes the per-millisecond sequence - counter explicitly. It is the caller's responsibility to increment - ``sequence_id`` for identifiers minted within the same millisecond and to - reset it once the clock advances. - - Args: - sequence_id: The per-millisecond sequence counter, in the range - ``[0, SEQUENCE_ID_MAX]``. - node_id: The identifier of this node, in the range ``[0, NODE_ID_MAX]``. - Optional; defaults to ``NODE_ID_DEFAULT``. - epoch_ms: The start of the epoch as Unix milliseconds. Optional; - defaults to the original Twitter epoch (2010-11-04 01:42:54.657 - UTC). - - Returns: - The Snowflake identifier as a positive 63-bit integer, or ``None`` if - ``node_id`` is outside ``[0, NODE_ID_MAX]``, ``sequence_id`` is outside - ``[0, SEQUENCE_ID_MAX]``, or the elapsed time no longer fits in the - timestamp field (roughly 69 years after ``epoch_ms``). In each of those - cases an explanatory message is printed to stdout first. - """ - # TODO: реализуйте функцию - return 0 + return ( + (timestamp_ms << (NODE_ID_BITS + SEQUENCE_ID_BITS)) | + (node_id << SEQUENCE_ID_BITS) | + sequence_id + ) From 25bb0a9398067773f13d1640ebe8bb1460d62b4a Mon Sep 17 00:00:00 2001 From: spol Date: Fri, 25 Sep 2026 18:13:57 +0300 Subject: [PATCH 5/9] Solve task 1 (finished) From ae4b181d669278013e1ed1a15cef51a7488e174a Mon Sep 17 00:00:00 2001 From: spol Date: Fri, 25 Sep 2026 18:14:36 +0300 Subject: [PATCH 6/9] Solve task 1 (finished) --- src/part1/constants.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/part1/constants.py b/src/part1/constants.py index 0c933fbf..88c88241 100644 --- a/src/part1/constants.py +++ b/src/part1/constants.py @@ -17,4 +17,4 @@ SEQUENCE_ID_MAX: Final[int] = 2**SEQUENCE_ID_BITS - 1 # Здесь можно добавить собственные вспомогательные константы -# (например, сдвиги полей при сборке идентификатора). +# (например, сдвиги полей при сборке идентификатора) From 8c6c49b6546513d802a88fed3bb273f6808f6830 Mon Sep 17 00:00:00 2001 From: spol Date: Fri, 25 Sep 2026 18:15:02 +0300 Subject: [PATCH 7/9] Solve task 1 (finished) --- src/part1/snowflake.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/part1/snowflake.py b/src/part1/snowflake.py index de57e15e..2ad44761 100644 --- a/src/part1/snowflake.py +++ b/src/part1/snowflake.py @@ -25,7 +25,7 @@ def read_current_millis(epoch_ms: int) -> int: - unix_epoch_time = time.time_ns() // 1_000_000 # get current time in milliseconds + unix_epoch_time = time.time_ns() // 1_000_000 #get current time in milliseconds return (unix_epoch_time - epoch_ms) From ae0fa3297f4d89261bc65c948454a27421b41a87 Mon Sep 17 00:00:00 2001 From: SpiridonovOleg Date: Fri, 25 Sep 2026 18:47:46 +0300 Subject: [PATCH 8/9] Solve task 1 --- src/part1/constants.py | 1 + src/part1/snowflake.py | 31 ++++++++++++++++++++----------- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/src/part1/constants.py b/src/part1/constants.py index 88c88241..08d51bbc 100644 --- a/src/part1/constants.py +++ b/src/part1/constants.py @@ -1,5 +1,6 @@ from typing import Final + # Twitter's original Snowflake epoch: 2010-11-04 01:42:54.657 UTC. EPOCH_MS_DEFAULT: Final[int] = 1288834974657 diff --git a/src/part1/snowflake.py b/src/part1/snowflake.py index 2ad44761..965e604d 100644 --- a/src/part1/snowflake.py +++ b/src/part1/snowflake.py @@ -13,48 +13,57 @@ :func:`decode_node_id` and :func:`decode_sequence_id`. """ -import time # noqa: F401 +import time -from .constants import ( # noqa: F401 +from .constants import ( EPOCH_MS_DEFAULT, + NODE_ID_BITS, NODE_ID_DEFAULT, NODE_ID_MAX, + SEQUENCE_ID_BITS, SEQUENCE_ID_MAX, TIMESTAMP_MS_MAX, ) def read_current_millis(epoch_ms: int) -> int: - unix_epoch_time = time.time_ns() // 1_000_000 #get current time in milliseconds - return (unix_epoch_time - epoch_ms) + unix_epoch_time = time.time_ns() // 1_000_000 # get current time in milliseconds + return unix_epoch_time - epoch_ms def decode_timestamp_ms(snowflake_id: int, epoch_ms: int = EPOCH_MS_DEFAULT) -> int: - return (snowflake_id >> (NODE_ID_BITS + SEQUENCE_ID_BITS)) + epoch_ms + return (snowflake_id >> (NODE_ID_BITS + SEQUENCE_ID_BITS)) + epoch_ms def decode_node_id(snowflake_id: int) -> int: - return (snowflake_id >> SEQUENCE_ID_BITS) & NODE_ID_MAX + return (snowflake_id >> SEQUENCE_ID_BITS) & NODE_ID_MAX def decode_sequence_id(snowflake_id: int) -> int: return snowflake_id & SEQUENCE_ID_MAX -def generate_snowflake_id(sequence_id: int, node_id: int = NODE_ID_DEFAULT, epoch_ms: int = EPOCH_MS_DEFAULT) -> int | None: + +def generate_snowflake_id( + sequence_id: int, node_id: int = NODE_ID_DEFAULT, epoch_ms: int = EPOCH_MS_DEFAULT +) -> int | None: timestamp_ms = read_current_millis(epoch_ms) if node_id < 0 or node_id > NODE_ID_MAX: print(f"Invalid node_id: {node_id}, node_id must be in [0, {NODE_ID_MAX}].") return None if sequence_id < 0 or sequence_id > SEQUENCE_ID_MAX: - print(f"Invalid sequence_id: {sequence_id}, sequence_id must be in [0, {SEQUENCE_ID_MAX}].") + print( + f"Invalid sequence_id: {sequence_id}, sequence_id must be in [0, {SEQUENCE_ID_MAX}]." + ) return None if timestamp_ms < 0 or timestamp_ms > TIMESTAMP_MS_MAX: print("overflows") return None return ( - (timestamp_ms << (NODE_ID_BITS + SEQUENCE_ID_BITS)) | - (node_id << SEQUENCE_ID_BITS) | - sequence_id + (timestamp_ms << (NODE_ID_BITS + SEQUENCE_ID_BITS)) + | (node_id << SEQUENCE_ID_BITS) + | sequence_id ) + +print(decode_timestamp_ms(generate_snowflake_id(0,))) From 6269b68cc48e51df7d52945e41359ac8c0129d4d Mon Sep 17 00:00:00 2001 From: spol Date: Fri, 25 Sep 2026 18:50:34 +0300 Subject: [PATCH 9/9] Solve task 1 (finished) --- src/part1/snowflake.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/part1/snowflake.py b/src/part1/snowflake.py index 965e604d..f6b5b2c1 100644 --- a/src/part1/snowflake.py +++ b/src/part1/snowflake.py @@ -66,4 +66,3 @@ def generate_snowflake_id( | sequence_id ) -print(decode_timestamp_ms(generate_snowflake_id(0,)))