#!/usr/bin/env python # -*- coding: utf-8 -*- # @Time : 2022/9/10 10:17 # @Author : old tom # @File : fu_date.py # @Project : Futool # @Desc : 日期时间工具 import time from datetime import datetime, date, timedelta import calendar # 毫秒单位 MILLISECOND_UNIT = 1000 # 1小时3600秒 ONE_HOUR_SECOND = 3600 # 上午下午分界 AM_PM_DIV = 11 # 一周7天 ONE_WEEK_DAYS = 7 # 日期时间格式化转换 FMT_MAPPING = { 'yyyy-MM-dd': '%Y-%m-%d', 'yyyyMMdd': '%Y%m%d', 'yyyy-MM-dd hh:mm:ss': '%Y-%m-%d %I:%M:%S', 'yyyy-MM-dd hh24:mm:ss': '%Y-%m-%d %H:%M:%S', 'yyyy-MM-dd HH:mm:ss': '%Y-%m-%d %H:%M:%S' } def current_year() -> int: """ 本年 :return: """ return datetime.now().year def current_month() -> int: """ 本月 :return: """ return datetime.now().month def current_day() -> int: return datetime.now().day def current_date() -> str: return str(datetime.now().date()) def current_datetime(fmt='yyyy-MM-dd hh24:mm:ss') -> str: """ 获取当前日期时间 :param fmt: :return: """ return datetime.now().strftime(FMT_MAPPING[fmt]) def current_time(fmt='s') -> int: """ 获取当前时间绝对秒 :param fmt: s: 秒 ms:毫秒 ns:纳秒 :return: """ time_jar = { 's': int(time.time()), 'ms': int(time.time() * MILLISECOND_UNIT), 'ns': time.time_ns() } return time_jar[fmt] def current_timestamp(): """ 当前时间戳 :return: """ return datetime.now().timestamp() def format_datetime_str(dt: str, fmt='yyyy-MM-dd hh24:mm:ss') -> datetime: """ 格式化日期时间字符串 :param dt: 日期时间字符串 :param fmt: 格式化,例:yyyy-MM-dd :return: datetime对象 """ return datetime.strptime(dt, FMT_MAPPING[fmt]) def format_date_str(dt: str, fmt='yyyy-MM-dd') -> date: """ 格式化日期字符串 :param dt: 日期字符串 :param fmt: yyyy-MM-dd :return: """ return datetime.strptime(dt, FMT_MAPPING[fmt]).date() def datetime_2_second(dt: str, fmt='yyyy-MM-dd hh24:mm:ss') -> int: """ 日期时间字符串转绝对秒 :param dt: 日期时间字符串 yyyy-MM-dd hh:mm:ss 格式 :param fmt: 格式化函数 :return: """ return int(format_datetime_str(dt, fmt).timestamp()) def sec_2_datatime(sec_time: int, fmt='yyyy-MM-dd hh24:mm:ss') -> str: """ 绝对秒转日期时间 :param sec_time: :param fmt: 格式化函数 :return: """ timed = time.localtime(sec_time) return time.strftime(FMT_MAPPING[fmt], timed) def is_leap(year: int) -> bool: """ 是否闰年 :param year: :return: """ return calendar.isleap(year) def begin_of_week(date_str: str, fmt='yyyy-MM-dd') -> str: """ 周开始日期 :param date_str: 年 :param fmt: 格式化 :return: """ formated_dt = format_date_str(date_str, fmt) week_idx = weekday(date_str, fmt) return date_str if week_idx == 0 else str(formated_dt - timedelta(days=week_idx)) def end_of_week(date_str: str, fmt='yyyy-MM-dd') -> str: """ 周结束日期 :param date_str: 年 :param fmt: 格式化 :return: """ formated_dt = format_date_str(date_str, fmt) week_idx = weekday(date_str, fmt) return date_str if week_idx == 6 else str(formated_dt + timedelta(days=(6 - week_idx))) def end_of_month(y, m) -> int: """ 月结束日期 :param y 年 :param m 月 :return: """ return calendar.monthrange(y, m)[1] def weekday(date_str: str, fmt='yyyy-MM-dd') -> int: """ 返回日期是周几 :param date_str: 年 :param fmt: 格式化 :return: 0-7 ,0:周一 """ fmted_date = format_datetime_str(date_str, fmt) return calendar.weekday(fmted_date.year, fmted_date.month, fmted_date.day) def age(birth: str, compare_date: str, fmt='yyyy-MM-dd') -> int: """ 年龄计算 :param birth: 生日 :param compare_date: 被比较日期 :param fmt: 日期格式化 yyyy-MM-dd|yyyyMMdd :return: """ fmt_birth = format_date_str(birth, fmt) fmt_compare = format_date_str(compare_date, fmt) birth_m = fmt_birth.replace(year=fmt_compare.year) return fmt_compare.year - fmt_birth.year if fmt_compare > birth_m else fmt_compare.year - fmt_birth.year - 1 def age_of_now(birth: str) -> int: """ 当前年龄 :param birth: 出生日期 :return: """ return age(birth, current_datetime('yyyy-MM-dd')) def between(dt_1: str, dt_2: str, fmt='yyyy-MM-dd', time_unit='day') -> int: """ 计算两个时间差 :param dt_1: 时间1 日期或日期时间 :param dt_2: 时间2 日期或日期时间 :param fmt: 格式化 :param time_unit: 时间单位 day: 天,hour: 小时 ,minute:分钟,second:秒 :return: """ fmt_dt1, fmt_dt2 = format_datetime_str(dt_1, fmt), format_datetime_str(dt_2, fmt) return abs({ 'day': (fmt_dt1 - fmt_dt2).days, 'hour': int(fmt_dt1.timestamp() - fmt_dt2.timestamp()) / ONE_HOUR_SECOND, 'second': int(fmt_dt1.timestamp() - fmt_dt2.timestamp()) }[time_unit]) def time_offset(start_dt: str, offset: int, fmt='yyyy-MM-dd HH:mm:ss', time_unit='day') -> datetime: """ 时间偏移计算,例:计算相隔N天后的日期 :param start_dt: 开始日期(日期时间) :param fmt: 时间格式化 :param offset: 偏移量,支持正负数 :param time_unit: 偏移量单位 :return: """ fmt_dt = format_datetime_str(start_dt, fmt) return {'day': fmt_dt + timedelta(days=offset), 'hour': fmt_dt + timedelta(hours=offset), 'second': fmt_dt + timedelta(seconds=offset)}[time_unit] def is_am(dt: str, fmt='yyyy-MM-dd HH:mm:ss') -> bool: """ 是否上午 :param dt: :param fmt: :return: """ fmt_dt = format_datetime_str(dt, fmt) return fmt_dt.hour <= AM_PM_DIV def is_pm(dt: str, fmt='yyyy-MM-dd HH:mm:ss') -> bool: """ 是否下午 :param dt: :param fmt: :return: """ fmt_dt = format_datetime_str(dt, fmt) return fmt_dt.hour > AM_PM_DIV def next_week(fmt='yyyy-MM-dd HH:mm:ss') -> datetime: """ 下周同一天 :return: """ now = current_datetime(fmt) return time_offset(now, ONE_WEEK_DAYS, fmt) def next_month() -> datetime: """ 下个月同一天 :return: """ return datetime.now().replace(month=current_month() + 1)