Pyjoyment 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- Pyjo/App/ASGI.py +735 -0
- Pyjo/App/CGI.py +773 -0
- Pyjo/App/FastCGI.py +631 -0
- Pyjo/App/Lambda.py +987 -0
- Pyjo/App/WSGI.py +427 -0
- Pyjo/App/__init__.py +409 -0
- Pyjo/Asset/File.py +377 -0
- Pyjo/Asset/Memory.py +235 -0
- Pyjo/Asset/__init__.py +200 -0
- Pyjo/Base.py +215 -0
- Pyjo/Cache.py +119 -0
- Pyjo/Collection.py +570 -0
- Pyjo/Content/MultiPart.py +325 -0
- Pyjo/Content/Single.py +193 -0
- Pyjo/Content/__init__.py +806 -0
- Pyjo/Cookie/Request.py +90 -0
- Pyjo/Cookie/Response.py +294 -0
- Pyjo/Cookie/__init__.py +143 -0
- Pyjo/DOM/CSS.py +1019 -0
- Pyjo/DOM/HTML.py +550 -0
- Pyjo/DOM/__init__.py +1329 -0
- Pyjo/Date.py +294 -0
- Pyjo/EventEmitter.py +522 -0
- Pyjo/Exception.py +494 -0
- Pyjo/File.py +959 -0
- Pyjo/GetOpt.py +605 -0
- Pyjo/Headers.py +760 -0
- Pyjo/HelloWorld.py +77 -0
- Pyjo/Home.py +109 -0
- Pyjo/IOLoop/ChildProcess.py +591 -0
- Pyjo/IOLoop/Client.py +736 -0
- Pyjo/IOLoop/Datagram.py +982 -0
- Pyjo/IOLoop/Messages.py +664 -0
- Pyjo/IOLoop/Server.py +458 -0
- Pyjo/IOLoop/Stdio.py +446 -0
- Pyjo/IOLoop/Stream.py +644 -0
- Pyjo/IOLoop/Subprocess.py +419 -0
- Pyjo/IOLoop/TLS.py +360 -0
- Pyjo/IOLoop/__init__.py +1036 -0
- Pyjo/IOLoop/certs/README.md +41 -0
- Pyjo/IOLoop/certs/ca.crt +20 -0
- Pyjo/IOLoop/certs/server.crt +21 -0
- Pyjo/IOLoop/certs/server.key +28 -0
- Pyjo/JSON/Pointer.py +135 -0
- Pyjo/JSON/RPC.py +772 -0
- Pyjo/JSON/Schema.py +2506 -0
- Pyjo/JSON/__init__.py +573 -0
- Pyjo/Loader.py +342 -0
- Pyjo/Log.py +723 -0
- Pyjo/Message/Request.py +725 -0
- Pyjo/Message/Response.py +476 -0
- Pyjo/Message/__init__.py +830 -0
- Pyjo/Parameters.py +472 -0
- Pyjo/Path.py +419 -0
- Pyjo/Promise.py +894 -0
- Pyjo/Prove.py +1305 -0
- Pyjo/Reactor/Asyncio.py +854 -0
- Pyjo/Reactor/Poll.py +439 -0
- Pyjo/Reactor/__init__.py +525 -0
- Pyjo/SSE.py +119 -0
- Pyjo/Server/ASGI.py +486 -0
- Pyjo/Server/CGI.py +259 -0
- Pyjo/Server/Daemon.py +1007 -0
- Pyjo/Server/FastCGI.py +517 -0
- Pyjo/Server/Hot/__init__.py +687 -0
- Pyjo/Server/Hot/__main__.py +5 -0
- Pyjo/Server/Lambda.py +641 -0
- Pyjo/Server/Prefork.py +917 -0
- Pyjo/Server/Prethread.py +394 -0
- Pyjo/Server/Reload/Backend/Poll.py +114 -0
- Pyjo/Server/Reload/Backend/__init__.py +126 -0
- Pyjo/Server/Reload/__init__.py +482 -0
- Pyjo/Server/Reload/__main__.py +5 -0
- Pyjo/Server/Stdio.py +228 -0
- Pyjo/Server/WSGI.py +349 -0
- Pyjo/Server/__init__.py +396 -0
- Pyjo/String/Bytes.py +532 -0
- Pyjo/String/HTML.py +210 -0
- Pyjo/String/Mixin.py +333 -0
- Pyjo/String/Template.py +470 -0
- Pyjo/String/Unicode.py +553 -0
- Pyjo/String/__init__.py +0 -0
- Pyjo/TOML.py +232 -0
- Pyjo/Template.py +1290 -0
- Pyjo/Test/Pyjo.py +1454 -0
- Pyjo/Test/__init__.py +1233 -0
- Pyjo/Test/pytest_plugin.py +305 -0
- Pyjo/Transaction/HTTP.py +374 -0
- Pyjo/Transaction/WebSocket.py +709 -0
- Pyjo/Transaction/__init__.py +429 -0
- Pyjo/URL/Template.py +459 -0
- Pyjo/URL/__init__.py +651 -0
- Pyjo/Upload.py +139 -0
- Pyjo/UserAgent/CookieJar.py +391 -0
- Pyjo/UserAgent/Proxy.py +138 -0
- Pyjo/UserAgent/Server.py +239 -0
- Pyjo/UserAgent/Transactor.py +766 -0
- Pyjo/UserAgent/__init__.py +1243 -0
- Pyjo/Util.py +3567 -0
- Pyjo/WebSocket.py +332 -0
- Pyjo/YAML.py +1167 -0
- Pyjo/__init__.py +441 -0
- Pyjo/__main__.py +35 -0
- Pyjo/py.typed +0 -0
- Pyjoyment/Command/Author/__init__.py +20 -0
- Pyjoyment/Command/Author/generate/__init__.py +106 -0
- Pyjoyment/Command/Author/generate/app.py +299 -0
- Pyjoyment/Command/Author/generate/dockerfile.py +281 -0
- Pyjoyment/Command/Author/generate/kubernetes.py +514 -0
- Pyjoyment/Command/Author/generate/lambda_zip.py +372 -0
- Pyjoyment/Command/Author/generate/lite_app.py +113 -0
- Pyjoyment/Command/Author/generate/plugin.py +267 -0
- Pyjoyment/Command/Author/generate/pyproject.py +123 -0
- Pyjoyment/Command/Author/inflate.py +101 -0
- Pyjoyment/Command/__init__.py +332 -0
- Pyjoyment/Command/asgi.py +92 -0
- Pyjoyment/Command/cgi.py +90 -0
- Pyjoyment/Command/daemon.py +160 -0
- Pyjoyment/Command/eval.py +128 -0
- Pyjoyment/Command/fastcgi.py +99 -0
- Pyjoyment/Command/get.py +305 -0
- Pyjoyment/Command/lambda.py +117 -0
- Pyjoyment/Command/prefork.py +181 -0
- Pyjoyment/Command/prethread.py +126 -0
- Pyjoyment/Command/routes.py +133 -0
- Pyjoyment/Command/stdio.py +92 -0
- Pyjoyment/Command/version.py +141 -0
- Pyjoyment/Command/wsgi.py +93 -0
- Pyjoyment/Commands.py +546 -0
- Pyjoyment/Controller.py +1307 -0
- Pyjoyment/HelloWorld.py +56 -0
- Pyjoyment/Lite.py +494 -0
- Pyjoyment/Plugin/AllowedHosts.py +205 -0
- Pyjoyment/Plugin/Config.py +248 -0
- Pyjoyment/Plugin/DefaultHelpers.py +1202 -0
- Pyjoyment/Plugin/EPLRenderer.py +134 -0
- Pyjoyment/Plugin/EPRenderer.py +212 -0
- Pyjoyment/Plugin/HeaderCondition.py +98 -0
- Pyjoyment/Plugin/Health.py +325 -0
- Pyjoyment/Plugin/JSONConfig.py +172 -0
- Pyjoyment/Plugin/Mount.py +223 -0
- Pyjoyment/Plugin/PyRenderer.py +209 -0
- Pyjoyment/Plugin/TOMLConfig.py +141 -0
- Pyjoyment/Plugin/TagHelpers.py +959 -0
- Pyjoyment/Plugin/YAMLConfig.py +178 -0
- Pyjoyment/Plugin/__init__.py +80 -0
- Pyjoyment/Plugins.py +215 -0
- Pyjoyment/Renderer.py +673 -0
- Pyjoyment/Routes/Match.py +251 -0
- Pyjoyment/Routes/Pattern.py +443 -0
- Pyjoyment/Routes/Route.py +827 -0
- Pyjoyment/Routes/__init__.py +419 -0
- Pyjoyment/Sessions.py +255 -0
- Pyjoyment/Static.py +421 -0
- Pyjoyment/Types.py +238 -0
- Pyjoyment/Validator/Validation.py +395 -0
- Pyjoyment/Validator/__init__.py +304 -0
- Pyjoyment/__init__.py +1083 -0
- Pyjoyment/__main__.py +5 -0
- Pyjoyment/py.typed +0 -0
- Pyjoyment/resources/public/favicon.ico +0 -0
- Pyjoyment/resources/public/favicon.svg +345 -0
- Pyjoyment/resources/public/pyjo/bootstrap/LICENSE +21 -0
- Pyjoyment/resources/public/pyjo/bootstrap/bootstrap.bundle.min.js.map +1 -0
- Pyjoyment/resources/public/pyjo/bootstrap/bootstrap.css +6 -0
- Pyjoyment/resources/public/pyjo/bootstrap/bootstrap.js +7 -0
- Pyjoyment/resources/public/pyjo/bootstrap/bootstrap.min.css.map +1 -0
- Pyjoyment/resources/public/pyjo/failunicat.png +0 -0
- Pyjoyment/resources/public/pyjo/failunicat.svg +50 -0
- Pyjoyment/resources/public/pyjo/highlight.js/LICENSE +29 -0
- Pyjoyment/resources/public/pyjo/highlight.js/highlight-mojo-dark.css +56 -0
- Pyjoyment/resources/public/pyjo/highlight.js/highlight.min.js +1262 -0
- Pyjoyment/resources/public/pyjo/highlight.js/pyjoyment.min.js +1 -0
- Pyjoyment/resources/public/pyjo/logo-black-4x.png +0 -0
- Pyjoyment/resources/public/pyjo/logo-black-4x.svg +346 -0
- Pyjoyment/resources/public/pyjo/logo-white-2x.png +0 -0
- Pyjoyment/resources/public/pyjo/logo-white-2x.svg +346 -0
- Pyjoyment/resources/public/pyjo/logo-white-4x.png +0 -0
- Pyjoyment/resources/public/pyjo/logo-white-4x.svg +346 -0
- Pyjoyment/resources/public/pyjo/logo-white.png +0 -0
- Pyjoyment/resources/public/pyjo/logo-white.svg +346 -0
- Pyjoyment/resources/public/pyjo/logo.png +0 -0
- Pyjoyment/resources/public/pyjo/logo.svg +346 -0
- Pyjoyment/resources/public/pyjo/notfound.png +0 -0
- Pyjoyment/resources/public/pyjo/notfound.svg +3 -0
- Pyjoyment/resources/public/pyjo/nounicat.png +0 -0
- Pyjoyment/resources/public/pyjo/nounicat.svg +5 -0
- Pyjoyment/resources/public/pyjo/pinstripe-dark.png +0 -0
- Pyjoyment/resources/public/pyjo/pinstripe-dark.svg +4 -0
- Pyjoyment/resources/public/pyjo/pinstripe-light.png +0 -0
- Pyjoyment/resources/public/pyjo/pinstripe-light.svg +4 -0
- Pyjoyment/resources/public/pyjo/pyjo.css +204 -0
- Pyjoyment/resources/templates/pyjo/debug.html.ep +346 -0
- Pyjoyment/resources/templates/pyjo/exception.html.ep +32 -0
- Pyjoyment/resources/templates/pyjo/not_found.html.ep +45 -0
- pyjoyment-0.1.0.dist-info/METADATA +376 -0
- pyjoyment-0.1.0.dist-info/RECORD +200 -0
- pyjoyment-0.1.0.dist-info/WHEEL +4 -0
- pyjoyment-0.1.0.dist-info/entry_points.txt +8 -0
- pyjoyment-0.1.0.dist-info/licenses/LICENSE +201 -0
Pyjo/Date.py
ADDED
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Pyjo.Date - HTTP date
|
|
3
|
+
=====================
|
|
4
|
+
::
|
|
5
|
+
|
|
6
|
+
from Pyjo.Date import Date
|
|
7
|
+
|
|
8
|
+
# Parse
|
|
9
|
+
date = Date('Sun, 06 Nov 1994 08:49:37 GMT')
|
|
10
|
+
print(date.epoch)
|
|
11
|
+
|
|
12
|
+
# Or import the module, as in Google Python Style Guide
|
|
13
|
+
|
|
14
|
+
import Pyjo.Date
|
|
15
|
+
|
|
16
|
+
import time
|
|
17
|
+
|
|
18
|
+
# Parse
|
|
19
|
+
date = Pyjo.Date.new('Sun, 06 Nov 1994 08:49:37 GMT')
|
|
20
|
+
print(date.epoch)
|
|
21
|
+
|
|
22
|
+
# Build
|
|
23
|
+
date = Pyjo.Date.new(time.time() + 60)
|
|
24
|
+
print(date)
|
|
25
|
+
|
|
26
|
+
:mod:`Pyjo.Date` implements HTTP date and time functions, based on :rfc:`7230`,
|
|
27
|
+
:rfc:`7231` and :rfc:`3339`.
|
|
28
|
+
|
|
29
|
+
See also
|
|
30
|
+
--------
|
|
31
|
+
|
|
32
|
+
:mod:`Pyjoyment`, https://mojolicious.org.
|
|
33
|
+
|
|
34
|
+
Ported from `Mojo::Date <https://github.com/mojolicious/mojo/blob/v9.49/lib/Mojo/Date.pm>`_
|
|
35
|
+
of Mojolicious 9.49.
|
|
36
|
+
|
|
37
|
+
Classes
|
|
38
|
+
-------
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
import Pyjo.Base
|
|
42
|
+
import Pyjo.String.Mixin
|
|
43
|
+
|
|
44
|
+
import calendar
|
|
45
|
+
import re
|
|
46
|
+
import time
|
|
47
|
+
|
|
48
|
+
from datetime import UTC, datetime
|
|
49
|
+
from typing import Self
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
RFC3339_RE = re.compile(
|
|
53
|
+
r"""
|
|
54
|
+
^(\d+)-(\d+)-(\d+)\D+(\d+):(\d+):(\d+(?:\.\d+)?) # Date and time
|
|
55
|
+
(?:Z|([+-])(\d+):(\d+))?$ # Offset
|
|
56
|
+
""",
|
|
57
|
+
re.X | re.I,
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
DAYS = ('Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat')
|
|
61
|
+
MONTHS = ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec')
|
|
62
|
+
MONTH_NUMBERS = {name: number for number, name in enumerate(MONTHS)}
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class Pyjo_Date(Pyjo.Base.object, Pyjo.String.Mixin.object):
|
|
66
|
+
"""
|
|
67
|
+
:mod:`Pyjo.Date` inherits all methods from :mod:`Pyjo.Base` and
|
|
68
|
+
:mod:`Pyjo.String.Mixin` and implements the following new ones.
|
|
69
|
+
"""
|
|
70
|
+
|
|
71
|
+
epoch: int | float | None
|
|
72
|
+
|
|
73
|
+
def __init__(self, date: str | float | datetime | None = None) -> None:
|
|
74
|
+
"""::
|
|
75
|
+
|
|
76
|
+
date = Pyjo.Date.new()
|
|
77
|
+
date = Pyjo.Date.new('Sun Nov 6 08:49:37 1994')
|
|
78
|
+
date = Pyjo.Date.new(datetime.now(UTC))
|
|
79
|
+
|
|
80
|
+
Construct a new :mod:`Pyjo.Date` object and :meth:`parse` date if necessary.
|
|
81
|
+
"""
|
|
82
|
+
|
|
83
|
+
self.epoch = int(time.time())
|
|
84
|
+
"""::
|
|
85
|
+
|
|
86
|
+
epoch = date.epoch
|
|
87
|
+
date.epoch = 784111777
|
|
88
|
+
|
|
89
|
+
Epoch seconds, defaults to the current time.
|
|
90
|
+
"""
|
|
91
|
+
|
|
92
|
+
if date is not None:
|
|
93
|
+
self.parse(date)
|
|
94
|
+
|
|
95
|
+
def __bool__(self) -> bool:
|
|
96
|
+
"""::
|
|
97
|
+
|
|
98
|
+
boolean = bool(date)
|
|
99
|
+
|
|
100
|
+
Always true.
|
|
101
|
+
"""
|
|
102
|
+
return True
|
|
103
|
+
|
|
104
|
+
# Not in Mojolicious: the epoch for the standard library
|
|
105
|
+
def __float__(self) -> float:
|
|
106
|
+
"""::
|
|
107
|
+
|
|
108
|
+
number = float(date)
|
|
109
|
+
|
|
110
|
+
The epoch, for the standard library. Before Python 3.15,
|
|
111
|
+
:meth:`datetime.datetime.fromtimestamp` and :func:`time.gmtime` take only an
|
|
112
|
+
``int`` or a ``float``, not an object that converts to one, so they get
|
|
113
|
+
``float(date)``. ::
|
|
114
|
+
|
|
115
|
+
# datetime.datetime(1994, 11, 6, 8, 49, 37, tzinfo=datetime.timezone.utc)
|
|
116
|
+
datetime.fromtimestamp(float(Pyjo.Date.new(784111777)), UTC)
|
|
117
|
+
"""
|
|
118
|
+
return float(self.epoch or 0)
|
|
119
|
+
|
|
120
|
+
# Not in Mojolicious: the epoch for the standard library
|
|
121
|
+
def __int__(self) -> int:
|
|
122
|
+
"""::
|
|
123
|
+
|
|
124
|
+
number = int(date)
|
|
125
|
+
|
|
126
|
+
The epoch in whole seconds, for the standard library.
|
|
127
|
+
"""
|
|
128
|
+
return int(self.epoch or 0)
|
|
129
|
+
|
|
130
|
+
def __str__(self) -> str:
|
|
131
|
+
"""::
|
|
132
|
+
|
|
133
|
+
string = str(date)
|
|
134
|
+
|
|
135
|
+
Alias for :meth:`to_str`.
|
|
136
|
+
"""
|
|
137
|
+
return self.to_str()
|
|
138
|
+
|
|
139
|
+
def parse(self, date: str | float | datetime) -> Self:
|
|
140
|
+
"""::
|
|
141
|
+
|
|
142
|
+
date = date.parse('Sun Nov 6 08:49:37 1994')
|
|
143
|
+
date = date.parse(datetime.now(UTC))
|
|
144
|
+
|
|
145
|
+
Parse date. A :class:`datetime.datetime` gives its timestamp, so a naive
|
|
146
|
+
one is local time, as for :meth:`datetime.datetime.timestamp`. ::
|
|
147
|
+
|
|
148
|
+
# Epoch
|
|
149
|
+
print(Pyjo.Date.new('784111777').epoch)
|
|
150
|
+
print(Pyjo.Date.new('784111777.21').epoch)
|
|
151
|
+
|
|
152
|
+
# RFC 822/1123
|
|
153
|
+
print(Pyjo.Date.new('Sun, 06 Nov 1994 08:49:37 GMT').epoch)
|
|
154
|
+
|
|
155
|
+
# RFC 850/1036
|
|
156
|
+
print(Pyjo.Date.new('Sunday, 06-Nov-94 08:49:37 GMT').epoch)
|
|
157
|
+
|
|
158
|
+
# Ansi C asctime()
|
|
159
|
+
print(Pyjo.Date.new('Sun Nov 6 08:49:37 1994').epoch)
|
|
160
|
+
|
|
161
|
+
# RFC 3339
|
|
162
|
+
print(Pyjo.Date.new('1994-11-06T08:49:37Z').epoch)
|
|
163
|
+
print(Pyjo.Date.new('1994-11-06T08:49:37').epoch)
|
|
164
|
+
print(Pyjo.Date.new('1994-11-06T08:49:37.21Z').epoch)
|
|
165
|
+
print(Pyjo.Date.new('1994-11-06T08:49:37+01:00').epoch)
|
|
166
|
+
print(Pyjo.Date.new('1994-11-06T08:49:37-01:00').epoch)
|
|
167
|
+
"""
|
|
168
|
+
# Not in Mojolicious: datetime of the standard library
|
|
169
|
+
if isinstance(date, datetime):
|
|
170
|
+
timestamp = date.timestamp()
|
|
171
|
+
self.epoch = int(timestamp) if timestamp.is_integer() else timestamp
|
|
172
|
+
return self
|
|
173
|
+
|
|
174
|
+
date = str(date)
|
|
175
|
+
|
|
176
|
+
# epoch (784111777)
|
|
177
|
+
if re.search(r'^\d+$|^\d+\.\d+$', date):
|
|
178
|
+
self.epoch = float(date) if '.' in date else int(date)
|
|
179
|
+
return self
|
|
180
|
+
|
|
181
|
+
# RFC 822/1123 (Sun, 06 Nov 1994 08:49:37 GMT)
|
|
182
|
+
# RFC 850/1036 (Sunday, 06-Nov-94 08:49:37 GMT)
|
|
183
|
+
offset = 0
|
|
184
|
+
if m := re.search(r'^\w+\W+(\d+)\W+(\w+)\W+(\d+)\W+(\d+):(\d+):(\d+)\W*\w+$', date):
|
|
185
|
+
day, month, year, h, mi, s = m[1], MONTH_NUMBERS.get(m[2]), m[3], m[4], m[5], m[6]
|
|
186
|
+
|
|
187
|
+
# RFC 3339 (1994-11-06T08:49:37Z)
|
|
188
|
+
elif m := RFC3339_RE.search(date):
|
|
189
|
+
year, month, day, h, mi, s = m[1], int(m[2]) - 1, m[3], m[4], m[5], m[6]
|
|
190
|
+
if m[7]:
|
|
191
|
+
offset = ((int(m[8]) * 3600) + (int(m[9]) * 60)) * (-1 if m[7] == '+' else 1)
|
|
192
|
+
|
|
193
|
+
# ANSI C asctime() (Sun Nov 6 08:49:37 1994)
|
|
194
|
+
elif m := re.search(r'^\w+\s+(\w+)\s+(\d+)\s+(\d+):(\d+):(\d+)\s+(\d+)$', date):
|
|
195
|
+
month, day, h, mi, s, year = MONTH_NUMBERS.get(m[1]), m[2], m[3], m[4], m[5], m[6]
|
|
196
|
+
|
|
197
|
+
# Invalid
|
|
198
|
+
else:
|
|
199
|
+
self.epoch = None
|
|
200
|
+
return self
|
|
201
|
+
|
|
202
|
+
epoch = _timegm(float(s), int(mi), int(h), int(day), month, int(year))
|
|
203
|
+
self.epoch = epoch + offset if epoch is not None and epoch + offset >= 0 else None
|
|
204
|
+
return self
|
|
205
|
+
|
|
206
|
+
# Not in Mojolicious: datetime of the standard library
|
|
207
|
+
def to_datetime(self) -> datetime:
|
|
208
|
+
"""::
|
|
209
|
+
|
|
210
|
+
dt = date.to_datetime()
|
|
211
|
+
|
|
212
|
+
Turn date into a :class:`datetime.datetime` in UTC, for the standard library. ::
|
|
213
|
+
|
|
214
|
+
# datetime.datetime(1994, 11, 6, 8, 49, 37, tzinfo=datetime.timezone.utc)
|
|
215
|
+
Pyjo.Date.new(784111777).to_datetime()
|
|
216
|
+
"""
|
|
217
|
+
return datetime.fromtimestamp(self.epoch or 0, UTC)
|
|
218
|
+
|
|
219
|
+
# Renamed from Mojolicious: to_datetime, the name of the conversion to the
|
|
220
|
+
# datetime of the standard library here
|
|
221
|
+
def to_rfc3339(self) -> str:
|
|
222
|
+
"""::
|
|
223
|
+
|
|
224
|
+
string = date.to_rfc3339()
|
|
225
|
+
|
|
226
|
+
Render :rfc:`3339` date and time. ::
|
|
227
|
+
|
|
228
|
+
# "1994-11-06T08:49:37Z"
|
|
229
|
+
Pyjo.Date.new(784111777).to_rfc3339()
|
|
230
|
+
|
|
231
|
+
# "1994-11-06T08:49:37.21Z"
|
|
232
|
+
Pyjo.Date.new(784111777.21).to_rfc3339()
|
|
233
|
+
"""
|
|
234
|
+
# RFC 3339 (1994-11-06T08:49:37Z)
|
|
235
|
+
epoch = self.epoch or 0
|
|
236
|
+
t = time.gmtime(epoch)
|
|
237
|
+
string = f'{t.tm_year:04d}-{t.tm_mon:02d}-{t.tm_mday:02d}T{t.tm_hour:02d}:{t.tm_min:02d}:{t.tm_sec:02d}'
|
|
238
|
+
m = re.search(r'(\.\d+)$', _number(epoch))
|
|
239
|
+
return string + (m[1] if m else '') + 'Z'
|
|
240
|
+
|
|
241
|
+
def to_str(self) -> str:
|
|
242
|
+
"""::
|
|
243
|
+
|
|
244
|
+
string = date.to_str()
|
|
245
|
+
|
|
246
|
+
Render date suitable for HTTP messages. ::
|
|
247
|
+
|
|
248
|
+
# "Sun, 06 Nov 1994 08:49:37 GMT"
|
|
249
|
+
Pyjo.Date.new(784111777).to_str()
|
|
250
|
+
"""
|
|
251
|
+
# RFC 7231 (Sun, 06 Nov 1994 08:49:37 GMT)
|
|
252
|
+
t = time.gmtime(self.epoch or 0)
|
|
253
|
+
# Python counts the days of the week from Monday, Perl from Sunday
|
|
254
|
+
day, month = DAYS[(t.tm_wday + 1) % 7], MONTHS[t.tm_mon - 1]
|
|
255
|
+
return f'{day}, {t.tm_mday:02d} {month} {t.tm_year:04d} {t.tm_hour:02d}:{t.tm_min:02d}:{t.tm_sec:02d} GMT'
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
def _number(number: int | float) -> str:
|
|
259
|
+
# A number as Perl stringifies it: no ".0" for a whole float
|
|
260
|
+
return repr(number) if isinstance(number, float) and not number.is_integer() else str(int(number))
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
def _timegm(s: float, mi: int, h: int, day: int, month: int | None, year: int) -> int | float | None:
|
|
264
|
+
# Time::Local's timegm, with None instead of an exception for a value out of
|
|
265
|
+
# range
|
|
266
|
+
|
|
267
|
+
# Years 0 to 99 are within 50 years of the current one, 100 to 999 count
|
|
268
|
+
# from 1900
|
|
269
|
+
if year < 100:
|
|
270
|
+
this_year = time.localtime().tm_year
|
|
271
|
+
year += this_year - this_year % 100
|
|
272
|
+
if year > this_year + 50:
|
|
273
|
+
year -= 100
|
|
274
|
+
elif year <= this_year - 50:
|
|
275
|
+
year += 100
|
|
276
|
+
elif year < 1000:
|
|
277
|
+
year += 1900
|
|
278
|
+
|
|
279
|
+
# Unlike Mojolicious: an unknown month name is invalid, where Perl takes undef
|
|
280
|
+
# as 0, January, with a warning; and a year after 9999 is invalid, where
|
|
281
|
+
# datetime, which calendar.timegm uses, ends
|
|
282
|
+
if month is None or not 0 <= month <= 11 or year > 9999:
|
|
283
|
+
return None
|
|
284
|
+
month_days = calendar.monthrange(2000 if calendar.isleap(year) else 2001, month + 1)[1]
|
|
285
|
+
if not (1 <= day <= month_days and 0 <= h <= 23 and 0 <= mi <= 59 and 0 <= s < 60):
|
|
286
|
+
return None
|
|
287
|
+
|
|
288
|
+
epoch = calendar.timegm((year, month + 1, day, h, mi, int(s), 0, 0, 0))
|
|
289
|
+
return epoch + (s - int(s)) if s != int(s) else epoch
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
new = Pyjo_Date.new
|
|
293
|
+
object = Pyjo_Date
|
|
294
|
+
Date = Pyjo_Date
|