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/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)