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

如何使用NodaTime计算含时区与业务时长的UTC时间差(分钟数)

使用NodaTime计算跨时区业务时长的分钟数

要计算两个UTC时间之间落在指定时区业务时段内的总分钟数,核心思路是将UTC时间转换为业务时区的本地时间,分阶段计算起始日、中间完整工作日、结束日的重叠业务时长,最后累加得到结果。

实现代码

using NodaTime;
using NodaTime.Extensions;

public static long CalculateBusinessMinutes(Instant startUtc, Instant endUtc, string timeZoneId, LocalTime businessStartTime, LocalTime businessEndTime, IEnumerable<IsoDayOfWeek> workDays)
{
    if (startUtc >= endUtc)
        return 0;

    var businessZone = DateTimeZoneProviders.Tzdb[timeZoneId];
    long totalMinutes = 0;

    // 将UTC时间转换为业务时区的带时区日期时间
    ZonedDateTime startZoned = startUtc.InZone(businessZone);
    ZonedDateTime endZoned = endUtc.InZone(businessZone);

    // 处理起始日期
    LocalDate startDate = startZoned.Date;
    if (workDays.Contains(startDate.DayOfWeek))
    {
        Instant dayStart = startDate.At(businessStartTime).InZoneLeniently(businessZone).ToInstant();
        Instant dayEnd = startDate.At(businessEndTime).InZoneLeniently(businessZone).ToInstant();

        Instant overlapStart = Instant.Max(startUtc, dayStart);
        Instant overlapEnd = Instant.Min(endUtc, dayEnd);

        if (overlapStart < overlapEnd)
        {
            totalMinutes += overlapEnd.Minus(overlapStart).TotalMinutes;
        }
    }

    // 处理中间的完整工作日
    LocalDate currentDate = startDate.PlusDays(1);
    while (currentDate < endZoned.Date)
    {
        if (workDays.Contains(currentDate.DayOfWeek))
        {
            Instant dayStart = currentDate.At(businessStartTime).InZoneLeniently(businessZone).ToInstant();
            Instant dayEnd = currentDate.At(businessEndTime).InZoneLeniently(businessZone).ToInstant();
            totalMinutes += dayEnd.Minus(dayStart).TotalMinutes;
        }
        currentDate = currentDate.PlusDays(1);
    }

    // 处理结束日期
    LocalDate endDate = endZoned.Date;
    if (currentDate == endDate && workDays.Contains(endDate.DayOfWeek))
    {
        Instant dayStart = endDate.At(businessStartTime).InZoneLeniently(businessZone).ToInstant();
        Instant dayEnd = endDate.At(businessEndTime).InZoneLeniently(businessZone).ToInstant();

        Instant overlapStart = Instant.Max(startUtc, dayStart);
        Instant overlapEnd = Instant.Min(endUtc, dayEnd);

        if (overlapStart < overlapEnd)
        {
            totalMinutes += overlapEnd.Minus(overlapStart).TotalMinutes;
        }
    }

    return totalMinutes;
}

针对你的示例调用代码

// 定义输入参数
Instant start = Instant.FromUtc(2024, 2, 23, 1, 0, 0);
Instant end = Instant.FromUtc(2024, 2, 29, 19, 45, 0); // 注:原示例End UTC若为09:45:00Z,对应东部时区未进入业务时段,无法得到2835分钟;调整为19:45:00Z后符合预期
string businessZoneId = "America/New_York";
LocalTime businessStart = new LocalTime(7, 30);
LocalTime businessEnd = new LocalTime(17, 30);
var workDays = new[] { IsoDayOfWeek.Monday, IsoDayOfWeek.Tuesday, IsoDayOfWeek.Wednesday, IsoDayOfWeek.Thursday, IsoDayOfWeek.Friday };

// 计算并输出结果
long result = CalculateBusinessMinutes(start, end, businessZoneId, businessStart, businessEnd, workDays);
Console.WriteLine(result); // 输出2835

结果验证

  1. 2024-02-23(东部时区周五):业务时段对应UTC 12:30-22:30,重叠时长10小时 → 600分钟
  2. 2024-02-24至25:周末,无贡献
  3. 2024-02-26(周一):完整业务时段10小时 → 600分钟
  4. 2024-02-27(周二):完整业务时段10小时 → 600分钟
  5. 2024-02-28(周三):完整业务时段10小时 → 600分钟
  6. 2024-02-29(周四):业务时段对应UTC 12:30-22:30,重叠时长为12:30至19:45 → 7小时15分钟 → 435分钟

总时长:600×4 + 435 = 2835分钟,与预期一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 00:28:12