You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django自定义过滤器实现跨天考勤时长计算问题求助

跨天考勤时长计算解决方案

核心思路

跨天考勤的本质是将单条跨日期的考勤记录拆分为多个单日片段,分别计算每个片段的时长后求和。例如:

  • 考勤记录:2024-05-20 22:00(上班)→ 2024-05-21 06:00(下班)
  • 拆分后:
    1. 2024-05-20:22:00 → 23:59:59,时长1小时59分59秒
    2. 2024-05-21:00:00:00 → 06:00,时长6小时
  • 总时长:7小时59分59秒

1. 修复calculate_daily_duration过滤器

替换custom_filters.py中的原有逻辑,添加跨天判断与拆分计算:

from django import template
from datetime import timedelta, datetime
from django.utils import timezone  # 若项目启用时区,需导入

register = template.Library()

@register.filter
def calculate_daily_duration(check_in, check_out):
    if not check_in or not check_out:
        return timedelta(0)
    
    # 统一转为时区感知时间(若项目未启用时区可删除此部分)
    if timezone.is_naive(check_in):
        check_in = timezone.make_aware(check_in)
    if timezone.is_naive(check_out):
        check_out = timezone.make_aware(check_out)
    
    # 判断是否为同一天考勤
    if check_in.date() == check_out.date():
        return check_out - check_in
    else:
        # 计算当日剩余时长:从上班时间到当日23:59:59
        end_of_day = timezone.make_aware(datetime.combine(check_in.date(), datetime.max.time()))
        duration_day1 = end_of_day - check_in
        
        # 计算次日时长:从次日00:00:00到下班时间
        start_of_next_day = timezone.make_aware(datetime.combine(check_out.date(), datetime.min.time()))
        duration_day2 = check_out - start_of_next_day
        
        # 返回总时长
        return duration_day1 + duration_day2

2. 按天拆分考勤记录(可选)

如果需要在模板中分别展示每日的考勤片段,新增一个过滤器用于拆分跨天记录:

@register.filter
def split_overtime_records(check_in, check_out):
    records = []
    if not check_in or not check_out:
        return records
    
    # 时区处理(同上)
    if timezone.is_naive(check_in):
        check_in = timezone.make_aware(check_in)
    if timezone.is_naive(check_out):
        check_out = timezone.make_aware(check_out)
    
    current_date = check_in.date()
    end_date = check_out.date()
    
    while current_date <= end_date:
        if current_date == check_in.date() and current_date == end_date:
            # 同一天的完整记录
            duration = check_out - check_in
            records.append({
                'date': current_date,
                'start': check_in,
                'end': check_out,
                'duration': duration
            })
        elif current_date == check_in.date():
            # 考勤起始日的片段
            end_of_day = timezone.make_aware(datetime.combine(current_date, datetime.max.time()))
            duration = end_of_day - check_in
            records.append({
                'date': current_date,
                'start': check_in,
                'end': end_of_day,
                'duration': duration
            })
        elif current_date == end_date:
            # 考勤结束日的片段
            start_of_day = timezone.make_aware(datetime.combine(current_date, datetime.min.time()))
            duration = check_out - start_of_day
            records.append({
                'date': current_date,
                'start': start_of_day,
                'end': check_out,
                'duration': duration
            })
        else:
            # 跨多天时的完整单日记录(如上班20号,下班22号,中间21号为完整一天)
            start_of_day = timezone.make_aware(datetime.combine(current_date, datetime.min.time()))
            end_of_day = timezone.make_aware(datetime.combine(current_date, datetime.max.time()))
            duration = end_of_day - start_of_day
            records.append({
                'date': current_date,
                'start': start_of_day,
                'end': end_of_day,
                'duration': duration
            })
        current_date += timedelta(days=1)
    
    return records

3. 模板中使用示例

仅展示总时长:

<p>考勤总时长: {{ attendance.check_in|calculate_daily_duration:attendance.check_out }}</p>

按天展示拆分后的考勤片段:

{% for record in attendance.check_in|split_overtime_records:attendance.check_out %}
    <div class="attendance-item">
        <h4>{{ record.date }}</h4>
        <p>时段: {{ record.start|date:"H:i" }} - {{ record.end|date:"H:i" }}</p>
        <p>当日时长: {{ record.duration }}</p>
    </div>
{% endfor %}

注意事项

  • 若项目未启用Django时区,可删除所有timezone.make_aware相关代码,直接使用原生datetime。
  • 确保模型中的check_in和check_out字段为DateTimeField类型,且存储的时间格式正确。

内容的提问来源于stack exchange,提问作者Markmeplease

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 06:00:31