jit-utils-backend 0.0.1__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.
- jit_utils/__init__.py +152 -0
- jit_utils/apiAuthSign.py +73 -0
- jit_utils/barcode.py +50 -0
- jit_utils/clsTool.py +71 -0
- jit_utils/config/__init__.py +11 -0
- jit_utils/config/case.py +77 -0
- jit_utils/config/config.py +90 -0
- jit_utils/config/exception.py +17 -0
- jit_utils/config/field.py +177 -0
- jit_utils/convert.py +169 -0
- jit_utils/decorator.py +58 -0
- jit_utils/exceptions.py +113 -0
- jit_utils/forwarder.py +113 -0
- jit_utils/matchTool.py +136 -0
- jit_utils/network.py +36 -0
- jit_utils/qrcode.py +60 -0
- jit_utils/signature.py +56 -0
- jit_utils/spaceSender.py +44 -0
- jit_utils/string.py +118 -0
- jit_utils/time.py +701 -0
- jit_utils/validator.py +26 -0
- jit_utils/workday_constants.py +72 -0
- jit_utils_backend-0.0.1.dist-info/METADATA +182 -0
- jit_utils_backend-0.0.1.dist-info/RECORD +32 -0
- jit_utils_backend-0.0.1.dist-info/WHEEL +5 -0
- jit_utils_backend-0.0.1.dist-info/top_level.txt +2 -0
- tests/__init__.py +4 -0
- tests/run_tests.py +102 -0
- tests/test_package_imports.py +199 -0
- tests/test_qrcode_barcode.py +182 -0
- tests/test_string_utils.py +174 -0
- tests/test_time_utils.py +185 -0
jit_utils/time.py
ADDED
@@ -0,0 +1,701 @@
|
|
1
|
+
# -*-coding:utf-8-*-
|
2
|
+
"""
|
3
|
+
Created on 2023/9/25
|
4
|
+
|
5
|
+
@author: 臧韬
|
6
|
+
|
7
|
+
@desc: 默认描述
|
8
|
+
"""
|
9
|
+
import datetime
|
10
|
+
import time
|
11
|
+
from operator import eq, ge, gt, le, lt, ne
|
12
|
+
|
13
|
+
import arrow
|
14
|
+
from dateutil import rrule
|
15
|
+
from dateutil.relativedelta import relativedelta
|
16
|
+
from dateutil.tz import tz
|
17
|
+
|
18
|
+
from .workday_constants import holidayDict, workdayDict
|
19
|
+
|
20
|
+
ONE_DAY_SECONDS = 24 * 60 * 60
|
21
|
+
ONE_WEEK_MSECONDS = 7 * 24 * 60 * 60
|
22
|
+
ONE_DAY_MSECONDS = 24 * 60 * 60 * 1000
|
23
|
+
HALF_MONTH_MSECONDS = 60 * 60 * 24 * 1000 * 15
|
24
|
+
ONE_MONTH_MSECONDS = 60 * 60 * 24 * 1000 * 30
|
25
|
+
ONE_YEAR_MSECONDS = 60 * 60 * 24 * 1000 * 365
|
26
|
+
|
27
|
+
timeZone = tz.tzlocal()
|
28
|
+
|
29
|
+
|
30
|
+
def get(date):
|
31
|
+
return arrow.get(date, tzinfo=timeZone)
|
32
|
+
|
33
|
+
|
34
|
+
def now():
|
35
|
+
"""
|
36
|
+
当前时间
|
37
|
+
:return:
|
38
|
+
"""
|
39
|
+
return arrow.now(tz=timeZone).naive
|
40
|
+
|
41
|
+
|
42
|
+
def today():
|
43
|
+
"""
|
44
|
+
今天
|
45
|
+
:return:
|
46
|
+
"""
|
47
|
+
return now().floor("day").naive
|
48
|
+
|
49
|
+
|
50
|
+
def dayShift(date, days):
|
51
|
+
"""
|
52
|
+
日期偏移
|
53
|
+
:param date:
|
54
|
+
:param days:
|
55
|
+
:return:
|
56
|
+
"""
|
57
|
+
return get(date).shift(days=days).naive
|
58
|
+
|
59
|
+
|
60
|
+
def monday():
|
61
|
+
"""
|
62
|
+
本周一
|
63
|
+
:return:
|
64
|
+
"""
|
65
|
+
return now().floor("week").naive
|
66
|
+
|
67
|
+
|
68
|
+
def weekShift(date, weeks):
|
69
|
+
"""
|
70
|
+
星期偏移
|
71
|
+
:return:
|
72
|
+
"""
|
73
|
+
return get(date).shift(weeks=weeks).naive
|
74
|
+
|
75
|
+
|
76
|
+
def monthStart():
|
77
|
+
"""
|
78
|
+
月初
|
79
|
+
:return:
|
80
|
+
"""
|
81
|
+
return now().floor("month").naive
|
82
|
+
|
83
|
+
|
84
|
+
def monthShift(date, months):
|
85
|
+
"""
|
86
|
+
月偏移
|
87
|
+
:return:
|
88
|
+
"""
|
89
|
+
return get(date).shift(months=months).naive
|
90
|
+
|
91
|
+
|
92
|
+
def quarterStart():
|
93
|
+
"""
|
94
|
+
本季度
|
95
|
+
:return:
|
96
|
+
"""
|
97
|
+
return now().floor("quarter").naive
|
98
|
+
|
99
|
+
|
100
|
+
def quarterShift(date, quarters):
|
101
|
+
"""
|
102
|
+
季度偏移
|
103
|
+
:param date:
|
104
|
+
:param quarters:
|
105
|
+
:return:
|
106
|
+
"""
|
107
|
+
return get(date).shift(quarters=quarters).naive
|
108
|
+
|
109
|
+
|
110
|
+
def yearStart():
|
111
|
+
"""
|
112
|
+
本年
|
113
|
+
:return:
|
114
|
+
"""
|
115
|
+
return now().floor("year").naive
|
116
|
+
|
117
|
+
|
118
|
+
def yearShift(date, years):
|
119
|
+
"""
|
120
|
+
年偏移
|
121
|
+
:param date:
|
122
|
+
:param years:
|
123
|
+
:return:
|
124
|
+
"""
|
125
|
+
return get(date).shift(years=years).naive
|
126
|
+
|
127
|
+
|
128
|
+
def getTimestamp():
|
129
|
+
return int(time.time() * 1000)
|
130
|
+
|
131
|
+
|
132
|
+
def timeStampToDateTime(ts):
|
133
|
+
# 带微秒需要去掉后三位
|
134
|
+
if ts >= 10**10:
|
135
|
+
ts //= 10**3
|
136
|
+
dt = datetime.datetime.fromtimestamp(ts)
|
137
|
+
return dt
|
138
|
+
|
139
|
+
|
140
|
+
def strToTimestamp(dateStr, arrowFmt="YYYY-MM-DD HH:mm:ss", datetimeFmt="%Y-%m-%d %H:%M:%S"):
|
141
|
+
"""
|
142
|
+
字符串转时间戳
|
143
|
+
"""
|
144
|
+
if isinstance(dateStr, datetime.datetime):
|
145
|
+
dateStr = datetime.datetime.strftime(dateStr, datetimeFmt)
|
146
|
+
return arrow.get(dateStr, arrowFmt).timestamp()
|
147
|
+
|
148
|
+
|
149
|
+
def timeStampToDate(ts):
|
150
|
+
return timeStampToDateTime(ts).date()
|
151
|
+
|
152
|
+
|
153
|
+
def datetime2string(dt, fmt="%Y-%m-%d"):
|
154
|
+
if isinstance(dt, datetime.datetime):
|
155
|
+
return datetime.datetime.strftime(dt, fmt)
|
156
|
+
else:
|
157
|
+
return ""
|
158
|
+
|
159
|
+
|
160
|
+
def currentTimedelta(*args, **kwargs):
|
161
|
+
return datetime.datetime.now() + datetime.timedelta(*args, **kwargs)
|
162
|
+
|
163
|
+
|
164
|
+
def nowNoMicrosecond():
|
165
|
+
"""获取不包含毫秒时间的当前时间"""
|
166
|
+
return datetime.datetime.now().replace(microsecond=0)
|
167
|
+
|
168
|
+
|
169
|
+
def formatNow(fmt="%Y-%m-%d"):
|
170
|
+
return datetime.datetime.strftime(datetime.datetime.now(), fmt)
|
171
|
+
|
172
|
+
|
173
|
+
def getNowTimestampFmt(fmt):
|
174
|
+
nowStr = formatNow(fmt=fmt)
|
175
|
+
dt = string2datetime(nowStr, fmt=fmt)
|
176
|
+
return datetime2timestamp(dt)
|
177
|
+
|
178
|
+
|
179
|
+
def datetime2timestamp(dt):
|
180
|
+
if not isinstance(dt, datetime.datetime):
|
181
|
+
return dt
|
182
|
+
return int(time.mktime(dt.timetuple()) * 1000)
|
183
|
+
|
184
|
+
|
185
|
+
def dateTimestamps(day=0):
|
186
|
+
"""生成账单日期 为前一天"""
|
187
|
+
dt = datetime.date.today() + datetime.timedelta(days=-day)
|
188
|
+
return int(time.mktime(dt.timetuple()) * 1000)
|
189
|
+
|
190
|
+
|
191
|
+
def timestamp2date(timeStamp):
|
192
|
+
"""timestamp date 转换"""
|
193
|
+
dt = datetime.datetime.fromtimestamp(timeStamp)
|
194
|
+
return dt.strftime("%Y-%m-%d")
|
195
|
+
|
196
|
+
|
197
|
+
def getEveryDate(beginDate, endDate):
|
198
|
+
"""获取 2个日期之间的所有日期"""
|
199
|
+
beginDate = timestamp2date(int(float(beginDate / 1000)))
|
200
|
+
endDate = timestamp2date(int(float(endDate / 1000)))
|
201
|
+
dateList = []
|
202
|
+
beginDate = datetime.datetime.strptime(beginDate, "%Y-%m-%d")
|
203
|
+
endDate = datetime.datetime.strptime(endDate, "%Y-%m-%d")
|
204
|
+
while beginDate <= endDate:
|
205
|
+
dateStr = int(time.mktime(beginDate.timetuple())) # beginDate.strftime("%Y-%m-%d")
|
206
|
+
dateList.append(dateStr)
|
207
|
+
beginDate += datetime.timedelta(days=1)
|
208
|
+
return dateList
|
209
|
+
|
210
|
+
|
211
|
+
def getXDayBefore(x, tsFlag=False):
|
212
|
+
"""获取x天前日期 tsFlag为True则返回时间戳"""
|
213
|
+
dt = datetime.datetime.now() - datetime.timedelta(days=x)
|
214
|
+
if tsFlag:
|
215
|
+
return int(dt.timestamp() * 1000)
|
216
|
+
return dt
|
217
|
+
|
218
|
+
|
219
|
+
def datetime2special(dt, days, hmstr):
|
220
|
+
"""
|
221
|
+
2018-11-22 21:11:25
|
222
|
+
@param days: 天数 1
|
223
|
+
@param hmstr: '09:00'
|
224
|
+
@return: 2018-11-23 09:00:00
|
225
|
+
"""
|
226
|
+
if days:
|
227
|
+
dt = dt + datetime.timedelta(days=days)
|
228
|
+
if hmstr:
|
229
|
+
hmList = hmstr.split(":")
|
230
|
+
dt = datatypes.replace(hour=int(hmList[0]))
|
231
|
+
dt = datatypes.replace(minute=int(hmList[-1]))
|
232
|
+
dt = datatypes.replace(second=0)
|
233
|
+
return dt
|
234
|
+
|
235
|
+
|
236
|
+
def string2datetime(dtStr, fmt="%Y-%m-%d"):
|
237
|
+
if dtStr:
|
238
|
+
return datetime.datetime.strptime(dtStr, fmt)
|
239
|
+
else:
|
240
|
+
return None
|
241
|
+
|
242
|
+
|
243
|
+
def string2date(dtStr, splitStr="-"):
|
244
|
+
"""splitStr 分割符,默认样式是 2020-10-05"""
|
245
|
+
if dtStr:
|
246
|
+
return datetime.date(*map(int, dtStr.split(splitStr)))
|
247
|
+
else:
|
248
|
+
return None
|
249
|
+
|
250
|
+
|
251
|
+
def datetimeYymmdd():
|
252
|
+
return str(datetime.datetime.now()).replace(" ", "").replace(":", "").replace(".", "").replace("-", "")[:-12]
|
253
|
+
|
254
|
+
|
255
|
+
def datetimeYymmddhhmmss():
|
256
|
+
return str(datetime.datetime.now()).replace(" ", "").replace(":", "").replace(".", "").replace("-", "")[:-6]
|
257
|
+
|
258
|
+
|
259
|
+
def specialYymmddhhmmss(ts):
|
260
|
+
dt = timestamp2datetime(ts)
|
261
|
+
return str(dt).replace(" ", "").replace(":", "").replace(".", "").replace("-", "")
|
262
|
+
|
263
|
+
|
264
|
+
def getZeroTimestamp(ts=None):
|
265
|
+
"""获取今天0点的时间戳"""
|
266
|
+
ts = ts or getTimestamp()
|
267
|
+
dt = timestamp2datetime(ts)
|
268
|
+
return datetime2timestamp(datetime.datetime(dt.year, dt.month, dt.day, 0, 0, 0))
|
269
|
+
|
270
|
+
|
271
|
+
def getNextZeroTimestamp(ts=None):
|
272
|
+
ts = ts or getTimestamp()
|
273
|
+
dt = timestamp2datetime(ts) + datetime.timedelta(days=1)
|
274
|
+
return datetime2timestamp(datetime.datetime(dt.year, dt.month, dt.day, 0, 0, 0))
|
275
|
+
|
276
|
+
|
277
|
+
def getNextMonthDay(ts=None):
|
278
|
+
ts = ts or getTimestamp()
|
279
|
+
date = timestamp2datetime(ts)
|
280
|
+
nextDt = date + relativedelta(months=1)
|
281
|
+
return datetime2timestamp(nextDt)
|
282
|
+
|
283
|
+
|
284
|
+
def getPrevMonthDay(ts=None):
|
285
|
+
ts = ts or getTimestamp()
|
286
|
+
date = timestamp2datetime(ts)
|
287
|
+
nextDt = date + relativedelta(months=-1)
|
288
|
+
return datetime2timestamp(nextDt)
|
289
|
+
|
290
|
+
|
291
|
+
def getPrevZeroTimestamp(ts=None):
|
292
|
+
"""获取昨天0点的时间戳"""
|
293
|
+
ts = ts or getTimestamp()
|
294
|
+
dt = timestamp2datetime(ts) + datetime.timedelta(days=-1)
|
295
|
+
return datetime2timestamp(datetime.datetime(dt.year, dt.month, dt.day, 0, 0, 0))
|
296
|
+
|
297
|
+
|
298
|
+
def getMonthStartTimestamp(ts=None):
|
299
|
+
ts = ts or getTimestamp()
|
300
|
+
dt = timestamp2datetime(ts)
|
301
|
+
dt = datetime.datetime(dt.year, dt.month, 1, 0, 0, 0)
|
302
|
+
return datetime2timestamp(dt)
|
303
|
+
|
304
|
+
|
305
|
+
def getNextMonthStartTimestamp(ts=None):
|
306
|
+
ts = ts or getTimestamp()
|
307
|
+
dt = timestamp2datetime(ts)
|
308
|
+
dt = dt + relativedelta(months=1)
|
309
|
+
dt = datetime.datetime(dt.year, dt.month, 1, 0, 0, 0)
|
310
|
+
return datetime2timestamp(dt)
|
311
|
+
|
312
|
+
|
313
|
+
def getReduceTimestamp(standTime):
|
314
|
+
return time.time() * 10 - standTime
|
315
|
+
|
316
|
+
|
317
|
+
def getTimestampSecond():
|
318
|
+
return int(time.time())
|
319
|
+
|
320
|
+
|
321
|
+
def getTodayStr():
|
322
|
+
return str(datetime.date.today())
|
323
|
+
|
324
|
+
|
325
|
+
def getSecondTimestamp(afterSeconds=0):
|
326
|
+
"""afterSeconds 多少秒后的时间"""
|
327
|
+
return int(time.time()) + afterSeconds
|
328
|
+
|
329
|
+
|
330
|
+
def getMinuteTimestamp():
|
331
|
+
now = datetime.datetime.now()
|
332
|
+
return int(time.mktime(now.timetuple())) - now.second
|
333
|
+
|
334
|
+
|
335
|
+
def timestamp2datetime(ts):
|
336
|
+
strSt = str(ts)
|
337
|
+
if len(strSt) > 10:
|
338
|
+
ts = int(strSt[:-3])
|
339
|
+
dt = datetime.datetime.fromtimestamp(ts)
|
340
|
+
return dt
|
341
|
+
|
342
|
+
|
343
|
+
def getNextMonthZeroTs(ts):
|
344
|
+
dt = timestamp2datetime(ts)
|
345
|
+
if dt.month == 12:
|
346
|
+
nextMonthDate = datetime.datetime(dt.year + 1, 1, 1)
|
347
|
+
else:
|
348
|
+
nextMonthDate = datetime.datetime(dt.year, dt.month + 1, 1)
|
349
|
+
return datetime2timestamp(nextMonthDate)
|
350
|
+
|
351
|
+
|
352
|
+
def timestamp2string(ts, fmt="%Y-%m-%d %H:%M:%S"):
|
353
|
+
dt = timestamp2datetime(ts)
|
354
|
+
return datetime2string(dt, fmt)
|
355
|
+
|
356
|
+
|
357
|
+
def cmpTsSameDay(ts1, ts2):
|
358
|
+
dt1 = timestamp2datetime(ts1)
|
359
|
+
dt2 = timestamp2datetime(ts2)
|
360
|
+
|
361
|
+
dtstr1 = datetime2string(dt1)
|
362
|
+
dtstr2 = datetime2string(dt2)
|
363
|
+
|
364
|
+
if dtstr1 and dtstr2 and dtstr1 == dtstr2:
|
365
|
+
return True
|
366
|
+
return False
|
367
|
+
|
368
|
+
|
369
|
+
def cmpTsMinutes(ts1, ts2):
|
370
|
+
return int((ts2 - ts1) / (1000 * 60))
|
371
|
+
|
372
|
+
|
373
|
+
def formatStr(jsfmtstr):
|
374
|
+
return (
|
375
|
+
jsfmtstr.replace("YYYY", "%Y")
|
376
|
+
.replace("MM", "ppp")
|
377
|
+
.replace("M", "%m")
|
378
|
+
.replace("DD", "ooo")
|
379
|
+
.replace("D", "%d")
|
380
|
+
.replace("HH", "%H")
|
381
|
+
.replace("mm", "%M")
|
382
|
+
.replace("ss", "%S")
|
383
|
+
.replace("ppp", "%m")
|
384
|
+
.replace("ooo", "%d")
|
385
|
+
)
|
386
|
+
|
387
|
+
|
388
|
+
def formatMysqlStr(pyFmtStr):
|
389
|
+
return (
|
390
|
+
pyFmtStr.replace("YYYY", "%Y")
|
391
|
+
.replace("MM", "ppp")
|
392
|
+
.replace("M", "%m")
|
393
|
+
.replace("DD", "ooo")
|
394
|
+
.replace("D", "%d")
|
395
|
+
.replace("HH", "%H")
|
396
|
+
.replace("mm", "%i")
|
397
|
+
.replace("ss", "%S")
|
398
|
+
.replace("ppp", "%m")
|
399
|
+
.replace("ooo", "%d")
|
400
|
+
)
|
401
|
+
|
402
|
+
|
403
|
+
def nowYyyymmddhhmmss():
|
404
|
+
"""
|
405
|
+
@return: 当天时间 如 2018-12-12 20:57:43
|
406
|
+
"""
|
407
|
+
dtstr = str(datetime.datetime.now())
|
408
|
+
return dtstr.split(".")[0]
|
409
|
+
|
410
|
+
|
411
|
+
def nowYyyymmddhhmm():
|
412
|
+
"""
|
413
|
+
@return: 当天时间 如 2018-12-12 20:57
|
414
|
+
"""
|
415
|
+
dtstr = str(datetime.datetime.now())
|
416
|
+
return dtstr.rsplit(":", 1)[0]
|
417
|
+
|
418
|
+
|
419
|
+
def string2timestamp(string, fmt="%Y-%m-%d"):
|
420
|
+
return int(time.mktime(string2datetime(string, fmt=fmt).timetuple())) * 1000
|
421
|
+
|
422
|
+
|
423
|
+
def deltaTime(ts1, ts2):
|
424
|
+
"""
|
425
|
+
ts1 和 ts2 的时间差
|
426
|
+
"""
|
427
|
+
if len("%s" % ts1) == 13:
|
428
|
+
ts1 = ts1 / 1000.0
|
429
|
+
if len("%s" % ts2) == 13:
|
430
|
+
ts2 = ts2 / 1000.0
|
431
|
+
t1 = datetime.datetime.fromtimestamp(ts1)
|
432
|
+
t2 = datetime.datetime.fromtimestamp(ts2)
|
433
|
+
return t1 - t2
|
434
|
+
|
435
|
+
|
436
|
+
def isWorkday(dt):
|
437
|
+
dtStr = str(dt).rsplit(" ", 1)[0]
|
438
|
+
return bool(dtStr in workdayDict.keys() or (dt.weekday() <= 4 and dtStr not in holidayDict.keys()))
|
439
|
+
|
440
|
+
|
441
|
+
def getNextWorkTs(ts, splitDays):
|
442
|
+
d = 0
|
443
|
+
while d < splitDays:
|
444
|
+
ts += 24 * 60 * 60 * 1000
|
445
|
+
while not isWorkday(ts):
|
446
|
+
ts += 24 * 60 * 60 * 1000
|
447
|
+
d += 1
|
448
|
+
return ts
|
449
|
+
|
450
|
+
|
451
|
+
def getNextDatetime(n, unit, skipHoliday=False):
|
452
|
+
"""
|
453
|
+
获取下一个执行时间
|
454
|
+
dt: datetime.datetime
|
455
|
+
n: 天数 整数
|
456
|
+
skipHoliday: 是否跳过节假日
|
457
|
+
"""
|
458
|
+
startTime = datetime.datetime.now()
|
459
|
+
timeMap = {
|
460
|
+
"D": "days",
|
461
|
+
"H": "hours",
|
462
|
+
"M": "minutes",
|
463
|
+
}
|
464
|
+
if unit != "D":
|
465
|
+
timeOffset = datetime.timedelta(**{timeMap[unit]: n})
|
466
|
+
startTime = startTime + timeOffset
|
467
|
+
if skipHoliday and not isWorkday(startTime):
|
468
|
+
start = 1
|
469
|
+
while start < 100:
|
470
|
+
startTime += datetime.timedelta(days=1)
|
471
|
+
if isWorkday(startTime):
|
472
|
+
break
|
473
|
+
start += 1
|
474
|
+
else:
|
475
|
+
if skipHoliday:
|
476
|
+
d = 0
|
477
|
+
while d < n:
|
478
|
+
if isWorkday(startTime):
|
479
|
+
startTime += datetime.timedelta(days=1)
|
480
|
+
d += 1
|
481
|
+
else:
|
482
|
+
startTime += datetime.timedelta(days=n)
|
483
|
+
return startTime
|
484
|
+
|
485
|
+
|
486
|
+
def lastDayOfMonth(anyDay=datetime.date.today()):
|
487
|
+
"""获取月末最后一天, 返回date类型"""
|
488
|
+
nextMonth = anyDay.replace(day=28) + datetime.timedelta(days=4)
|
489
|
+
return nextMonth - datetime.timedelta(days=nextMonth.day)
|
490
|
+
|
491
|
+
|
492
|
+
def getXMonthZeroDt(ts, x):
|
493
|
+
"""获取x月后的第一天"""
|
494
|
+
for _ in range(x):
|
495
|
+
nextTs = getNextMonthZeroTs(ts)
|
496
|
+
ts = nextTs
|
497
|
+
return timestamp2datetime(ts)
|
498
|
+
|
499
|
+
|
500
|
+
def getFirstWorkday(dt):
|
501
|
+
"""获取当月第一个工作日"""
|
502
|
+
firstDt = datatypes.replace(day=1)
|
503
|
+
firstDs = datetime2timestamp(firstDt)
|
504
|
+
while not isWorkday(firstDs):
|
505
|
+
firstDt += relativedelta(days=1)
|
506
|
+
firstDs = datetime2timestamp(firstDt)
|
507
|
+
return firstDt
|
508
|
+
|
509
|
+
|
510
|
+
def getLastWorkday(dt):
|
511
|
+
"""获取当月最后一个工作日"""
|
512
|
+
lastDay = lastDayOfMonth(dt)
|
513
|
+
lastDt = datatypes.replace(day=lastDay.day)
|
514
|
+
lastTs = datetime2timestamp(lastDt)
|
515
|
+
while not isWorkday(lastTs):
|
516
|
+
lastDt -= relativedelta(days=1)
|
517
|
+
lastTs = datetime2timestamp(lastDt)
|
518
|
+
return lastDt
|
519
|
+
|
520
|
+
|
521
|
+
def getDeltaDayTime(t1, t2, unit=rrule.DAILY, fmt="YYYY-MM-DD HH:mm:ss"):
|
522
|
+
"""
|
523
|
+
获取时间差值 t2 - t1, 单位: day
|
524
|
+
param t1: 时间1, 字符串 或者 datetime
|
525
|
+
param t2: 时间2, 字符串 或者 datetime
|
526
|
+
param t2: 时间2, 字符串 或者 datetime
|
527
|
+
param unit: 差值的具体单位, 默认为 day
|
528
|
+
return 具体的unit数, 向上兼容
|
529
|
+
ex:
|
530
|
+
1. t2 < t1时, 返回0
|
531
|
+
2. t2 - t1 小于1年时, 返回1;
|
532
|
+
2. t2 - t1 大于等于1年时, 返回 n + 1;
|
533
|
+
"""
|
534
|
+
# 将输入转换为 Arrow 对象
|
535
|
+
if isinstance(t1, str):
|
536
|
+
t1 = arrow.get(t1, fmt)
|
537
|
+
elif isinstance(t1, datetime.datetime):
|
538
|
+
t1 = arrow.get(t1)
|
539
|
+
if isinstance(t2, str):
|
540
|
+
t2 = arrow.get(t2, fmt)
|
541
|
+
elif isinstance(t2, datetime.datetime):
|
542
|
+
t2 = arrow.get(t2)
|
543
|
+
# 根据unit返回具体的差值
|
544
|
+
return rrule.rrule(freq=unit, dtstart=t1, until=t2).count()
|
545
|
+
|
546
|
+
|
547
|
+
def compareDatetime(dt1, op, dt2):
|
548
|
+
"""
|
549
|
+
比较两个datetime格式: 针对于两个datetime时区不同的情况
|
550
|
+
|
551
|
+
dt1 op dt2
|
552
|
+
:param dt1: 时间1(datetime格式1)
|
553
|
+
:param op: 比较符
|
554
|
+
:param dt2: 时间2(datetime格式2)
|
555
|
+
"""
|
556
|
+
# 定义比较操作符字典
|
557
|
+
ops = {
|
558
|
+
"==": eq,
|
559
|
+
"!=": ne,
|
560
|
+
"<": lt,
|
561
|
+
">": gt,
|
562
|
+
"<=": le,
|
563
|
+
">=": ge,
|
564
|
+
}
|
565
|
+
# 确保给定的操作符有效
|
566
|
+
if op not in ops:
|
567
|
+
raise ValueError("无效的比较操作符")
|
568
|
+
# 将两个datetime都转换为UTC时间
|
569
|
+
if dt1.tzinfo is not None and dt1.tzinfo.utcoffset(dt1) is not None:
|
570
|
+
dt1 = dt1.astimezone(datetime.timezone.utc)
|
571
|
+
else:
|
572
|
+
dt1 = dt1.replace(tzinfo=datetime.timezone.utc)
|
573
|
+
|
574
|
+
if dt2.tzinfo is not None and dt2.tzinfo.utcoffset(dt2) is not None:
|
575
|
+
dt2 = dt2.astimezone(datetime.timezone.utc)
|
576
|
+
else:
|
577
|
+
dt2 = dt2.replace(tzinfo=datetime.timezone.utc)
|
578
|
+
# 使用提供的操作符进行比较
|
579
|
+
return ops[op](dt1, dt2)
|
580
|
+
|
581
|
+
|
582
|
+
def getDelayTime(dateStr, count, unit="days", fmt="YYYY-MM-DD HH:mm:ss"):
|
583
|
+
"""
|
584
|
+
获取时间增加后的时间
|
585
|
+
param dateStr: 时间字符串
|
586
|
+
param count: 数值
|
587
|
+
param unit: 时间单位 (days, hours, minutes, seconds, 等)
|
588
|
+
param fmt: 时间格式字符串
|
589
|
+
返回后延的具体时间: 时间格式datetime.datetime
|
590
|
+
"""
|
591
|
+
# 使用 Arrow 解析输入的时间字符串
|
592
|
+
arrowT1 = arrow.get(dateStr, fmt)
|
593
|
+
# 将单位转换为 Arrow 支持的格式
|
594
|
+
unitSet = {"years", "quarters", "months", "weeks", "days", "hours", "minutes", "seconds"}
|
595
|
+
arrowUnit = unit if unit in unitSet else "days"
|
596
|
+
# 计算后延的时间并返回
|
597
|
+
delayedArrow = arrowT1.shift(**{arrowUnit: count})
|
598
|
+
return delayedArrow.datetime
|
599
|
+
|
600
|
+
|
601
|
+
def getDelayMonthTime(t1, months, fmt="%Y-%m-%d %H:%M:%S"):
|
602
|
+
"""
|
603
|
+
获取时间增加的天数值
|
604
|
+
param t1: datetime格式时间或字符串或者时间戳
|
605
|
+
param months: 月份
|
606
|
+
param fmt: 时间格式字符串
|
607
|
+
返回后延的具体时间: 时间格式datetime
|
608
|
+
"""
|
609
|
+
if isinstance(t1, datetime.datetime):
|
610
|
+
delayedTime = t1 + relativedelta(months=months)
|
611
|
+
elif isinstance(t1, str):
|
612
|
+
delayedTime = datetime.datetime.strptime(t1, fmt) + relativedelta(months=months)
|
613
|
+
elif isinstance(t1, int):
|
614
|
+
delayedTime = datetime.datetime.fromtimestamp(t1) + relativedelta(months=months)
|
615
|
+
else:
|
616
|
+
raise ValueError("不支持的时间格式")
|
617
|
+
return delayedTime
|
618
|
+
|
619
|
+
|
620
|
+
def getValidPeriodTime(expireTime, months, fmt="%Y-%m-%d %H:%M:%S"):
|
621
|
+
"""
|
622
|
+
获取生效的时间段
|
623
|
+
param t1: datetime格式时间或字符串或者时间戳
|
624
|
+
param expireTime: 过期时间, 字符串, 格式: "%Y-%m-%d %H:%M:%S"
|
625
|
+
param months: 月份
|
626
|
+
return startTime, endTime, 都是fmt格式的字符串
|
627
|
+
"""
|
628
|
+
startTime = expireTime
|
629
|
+
expireTime = string2datetime(expireTime, fmt=fmt)
|
630
|
+
currTime = datetime.datetime.now()
|
631
|
+
if expireTime < currTime:
|
632
|
+
# 如果过期时间比当前时间小(已过期), 直接从当前时间开始计算具体的生效时间
|
633
|
+
startTime = datetime2string(currTime, fmt=fmt)
|
634
|
+
endTime = datetime2string(getDelayMonthTime(currTime, months), fmt=fmt)
|
635
|
+
else:
|
636
|
+
# 如果过期时间比当前时间大(未过期), 需要从实际过期时间进行计算
|
637
|
+
endTime = datetime2string(getDelayMonthTime(expireTime, months), fmt=fmt)
|
638
|
+
return startTime, endTime
|
639
|
+
|
640
|
+
|
641
|
+
def deltaArrowTime(arrowDate, count, unit="minute"):
|
642
|
+
"""
|
643
|
+
时间推迟: 具体的时间按传入值, 推迟到指定时间
|
644
|
+
:param arrowDate: arrow对象
|
645
|
+
:param count: 推迟数值
|
646
|
+
:param unit: 具体单位
|
647
|
+
:return datetime.datetime格式
|
648
|
+
"""
|
649
|
+
# 定义时间单位映射关系
|
650
|
+
unitMapping = {
|
651
|
+
"second": "seconds",
|
652
|
+
"minute": "minutes",
|
653
|
+
"hour": "hours",
|
654
|
+
"day": "days",
|
655
|
+
"week": "weeks",
|
656
|
+
"month": "months",
|
657
|
+
"year": "years",
|
658
|
+
}
|
659
|
+
# 确保单位是有效的
|
660
|
+
if unit not in unitMapping:
|
661
|
+
raise ValueError("无效的时间单位")
|
662
|
+
# 将单位转换为 Arrow 支持的格式
|
663
|
+
arrowUnit = unitMapping[unit]
|
664
|
+
# 使用 shift() 方法进行时间推迟
|
665
|
+
delayedArrow = arrowDate.shift(**{arrowUnit: count})
|
666
|
+
# 将 Arrow 对象转换为 datetime.datetime 格式
|
667
|
+
return delayedArrow.datetime
|
668
|
+
|
669
|
+
|
670
|
+
def datetimeToStr(dt, fmt="YYYY-MM-DD"):
|
671
|
+
"""
|
672
|
+
将 datetime 对象转换为指定格式的字符串
|
673
|
+
:param dt: datetime 对象
|
674
|
+
:param fmt: 时间格式字符串
|
675
|
+
:return: 格式化后的字符串
|
676
|
+
"""
|
677
|
+
if isinstance(dt, datetime.datetime):
|
678
|
+
# 使用 Arrow 格式化日期时间
|
679
|
+
arrowDt = arrow.get(dt)
|
680
|
+
formattedStr = arrowDt.format(fmt)
|
681
|
+
return formattedStr
|
682
|
+
else:
|
683
|
+
return ""
|
684
|
+
|
685
|
+
|
686
|
+
def addYearsToDate(currDate, years, fmt="%Y-%m-%d %H:%M:%S"):
|
687
|
+
"""
|
688
|
+
给指定日期增加年数的日期
|
689
|
+
:param currDate: 指定日期, 字符串
|
690
|
+
:param years: 指定增加的年数
|
691
|
+
:param fmt: 日期格式
|
692
|
+
:return 日期
|
693
|
+
"""
|
694
|
+
# 使用 Arrow 解析输入的日期字符串
|
695
|
+
arrow_date = arrow.get(currDate, fmt)
|
696
|
+
|
697
|
+
# 添加指定年数
|
698
|
+
new_date = arrow_date.shift(years=years)
|
699
|
+
|
700
|
+
# 返回新日期对象的格式化字符串
|
701
|
+
return new_date.format(fmt)
|