mirror of
https://github.com/Rapptz/discord.py.git
synced 2026-03-05 03:02:49 +00:00
Add Discord timestamp converter and transformer
This commit is contained in:
@@ -23,6 +23,7 @@ DEALINGS IN THE SOFTWARE.
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
import datetime
|
||||||
import inspect
|
import inspect
|
||||||
|
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
@@ -52,7 +53,7 @@ from ..channel import StageChannel, VoiceChannel, TextChannel, CategoryChannel,
|
|||||||
from ..abc import GuildChannel
|
from ..abc import GuildChannel
|
||||||
from ..threads import Thread
|
from ..threads import Thread
|
||||||
from ..enums import Enum as InternalEnum, AppCommandOptionType, ChannelType, Locale
|
from ..enums import Enum as InternalEnum, AppCommandOptionType, ChannelType, Locale
|
||||||
from ..utils import MISSING, maybe_coroutine, _human_join
|
from ..utils import MISSING, maybe_coroutine, _human_join, TIMESTAMP_PATTERN
|
||||||
from ..user import User
|
from ..user import User
|
||||||
from ..role import Role
|
from ..role import Role
|
||||||
from ..member import Member
|
from ..member import Member
|
||||||
@@ -62,6 +63,7 @@ from .._types import ClientT
|
|||||||
__all__ = (
|
__all__ = (
|
||||||
'Transformer',
|
'Transformer',
|
||||||
'Transform',
|
'Transform',
|
||||||
|
'Timestamp',
|
||||||
'Range',
|
'Range',
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -681,6 +683,41 @@ class UnionChannelTransformer(BaseChannelTransformer[ClientT]):
|
|||||||
return resolved
|
return resolved
|
||||||
|
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
Timestamp = datetime.datetime
|
||||||
|
else:
|
||||||
|
|
||||||
|
class Timestamp(Transformer[ClientT]):
|
||||||
|
"""A type annotation that can be applied to a parameter for transforming a :ddocs:`Discord style timestamp <reference#message-formatting>` input to a
|
||||||
|
:class:`datetime.datetime`.
|
||||||
|
|
||||||
|
|
||||||
|
.. versionadded:: 2.7
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
Due to a Discord limitation, no timezone is provided with the input. The UTC timezone has been supplanted instead.
|
||||||
|
|
||||||
|
Examples
|
||||||
|
---------
|
||||||
|
|
||||||
|
.. code-block:: python3
|
||||||
|
|
||||||
|
@app_commands.command()
|
||||||
|
async def datetime(interaction: discord.Interaction, value: app_commands.Timestamp):
|
||||||
|
await interaction.response.send_message(value.isoformat())
|
||||||
|
"""
|
||||||
|
|
||||||
|
@property
|
||||||
|
def type(self) -> AppCommandOptionType:
|
||||||
|
return AppCommandOptionType.string
|
||||||
|
|
||||||
|
async def transform(self, interaction: Interaction[ClientT], value: Any, /):
|
||||||
|
match = TIMESTAMP_PATTERN.match(value)
|
||||||
|
if not match:
|
||||||
|
raise TransformerError(value, AppCommandOptionType.string, self)
|
||||||
|
return datetime.datetime.fromtimestamp(int(match[1]), tz=datetime.timezone.utc)
|
||||||
|
|
||||||
|
|
||||||
CHANNEL_TO_TYPES: Dict[Any, List[ChannelType]] = {
|
CHANNEL_TO_TYPES: Dict[Any, List[ChannelType]] = {
|
||||||
AppCommandChannel: [
|
AppCommandChannel: [
|
||||||
ChannelType.stage_voice,
|
ChannelType.stage_voice,
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ DEALINGS IN THE SOFTWARE.
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import datetime
|
||||||
import inspect
|
import inspect
|
||||||
import re
|
import re
|
||||||
from typing import (
|
from typing import (
|
||||||
@@ -86,6 +87,7 @@ __all__ = (
|
|||||||
'clean_content',
|
'clean_content',
|
||||||
'Greedy',
|
'Greedy',
|
||||||
'Range',
|
'Range',
|
||||||
|
'Timestamp',
|
||||||
'run_converters',
|
'run_converters',
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -893,6 +895,28 @@ class GuildStickerConverter(IDConverter[discord.GuildSticker]):
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
Timestamp = datetime.datetime
|
||||||
|
else:
|
||||||
|
|
||||||
|
class Timestamp(Converter[str]):
|
||||||
|
"""Converts to a :class:`datetime.datetime`.
|
||||||
|
|
||||||
|
Conversion is attempted based on the :ddocs:`Discord style timestamp <reference#message-formatting>` input format.
|
||||||
|
|
||||||
|
.. versionadded:: 2.7
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
Due to a Discord limitation, no timezone is provided with the input. The UTC timezone has been supplanted instead.
|
||||||
|
"""
|
||||||
|
|
||||||
|
async def convert(self, ctx: Context[BotT], argument: str) -> datetime.datetime:
|
||||||
|
match = discord.utils.TIMESTAMP_PATTERN.match(argument)
|
||||||
|
if not match:
|
||||||
|
raise BadTimestampArgument(argument)
|
||||||
|
return datetime.datetime.fromtimestamp(int(match[1]), tz=datetime.timezone.utc)
|
||||||
|
|
||||||
|
|
||||||
class ScheduledEventConverter(IDConverter[discord.ScheduledEvent]):
|
class ScheduledEventConverter(IDConverter[discord.ScheduledEvent]):
|
||||||
"""Converts to a :class:`~discord.ScheduledEvent`.
|
"""Converts to a :class:`~discord.ScheduledEvent`.
|
||||||
|
|
||||||
|
|||||||
@@ -79,6 +79,7 @@ __all__ = (
|
|||||||
'SoundboardSoundNotFound',
|
'SoundboardSoundNotFound',
|
||||||
'PartialEmojiConversionFailure',
|
'PartialEmojiConversionFailure',
|
||||||
'BadBoolArgument',
|
'BadBoolArgument',
|
||||||
|
'BadTimestampArgument',
|
||||||
'MissingRole',
|
'MissingRole',
|
||||||
'BotMissingRole',
|
'BotMissingRole',
|
||||||
'MissingAnyRole',
|
'MissingAnyRole',
|
||||||
@@ -602,6 +603,24 @@ class BadBoolArgument(BadArgument):
|
|||||||
super().__init__(f'{argument} is not a recognised boolean option')
|
super().__init__(f'{argument} is not a recognised boolean option')
|
||||||
|
|
||||||
|
|
||||||
|
class BadTimestampArgument(BadArgument):
|
||||||
|
"""Exception raised when a timestamp argument was not convertable.
|
||||||
|
|
||||||
|
This inherits from :exc:`BadArgument`
|
||||||
|
|
||||||
|
.. versionadded:: 2.7
|
||||||
|
|
||||||
|
Attributes
|
||||||
|
-----------
|
||||||
|
argument: :class:`str`
|
||||||
|
The datetime/timestamp argument supplied by the caller that was not a valid timestamp format.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, argument: str) -> None:
|
||||||
|
self.argument: str = argument
|
||||||
|
super().__init__(f'{argument} is not a recognised datetime or timestamp option')
|
||||||
|
|
||||||
|
|
||||||
class RangeError(BadArgument):
|
class RangeError(BadArgument):
|
||||||
"""Exception raised when an argument is out of range.
|
"""Exception raised when an argument is out of range.
|
||||||
|
|
||||||
|
|||||||
@@ -118,6 +118,7 @@ __all__ = (
|
|||||||
|
|
||||||
DISCORD_EPOCH = 1420070400000
|
DISCORD_EPOCH = 1420070400000
|
||||||
DEFAULT_FILE_SIZE_LIMIT_BYTES = 10485760
|
DEFAULT_FILE_SIZE_LIMIT_BYTES = 10485760
|
||||||
|
TIMESTAMP_PATTERN: re.Pattern[str] = re.compile(r'<t:(-?\d+)(?::[tTdDfFsSR])?>')
|
||||||
|
|
||||||
|
|
||||||
class _MissingSentinel:
|
class _MissingSentinel:
|
||||||
|
|||||||
@@ -536,6 +536,11 @@ Converters
|
|||||||
.. autoclass:: discord.ext.commands.SoundboardSoundConverter
|
.. autoclass:: discord.ext.commands.SoundboardSoundConverter
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
|
.. attributetable:: discord.ext.commands.Timestamp
|
||||||
|
|
||||||
|
.. autoclass:: discord.ext.commands.Timestamp
|
||||||
|
:members:
|
||||||
|
|
||||||
.. attributetable:: discord.ext.commands.clean_content
|
.. attributetable:: discord.ext.commands.clean_content
|
||||||
|
|
||||||
.. autoclass:: discord.ext.commands.clean_content
|
.. autoclass:: discord.ext.commands.clean_content
|
||||||
|
|||||||
@@ -1169,6 +1169,14 @@ Range
|
|||||||
.. autoclass:: discord.app_commands.Range
|
.. autoclass:: discord.app_commands.Range
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
|
Timestamp
|
||||||
|
++++++++++
|
||||||
|
|
||||||
|
.. attributetable:: discord.app_commands.Timestamp
|
||||||
|
|
||||||
|
.. autoclass:: discord.app_commands.Timestamp
|
||||||
|
:members:
|
||||||
|
|
||||||
Translations
|
Translations
|
||||||
~~~~~~~~~~~~~
|
~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user