微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

使用 DotNet 在本地一天中的小时数

如何解决使用 DotNet 在本地一天中的小时数

dotnet 中是否有任何内置 api 会告诉您在指定的一天内有多少小时?

这假设 API 会支持给定时区的夏令时。因此,对于从格林威治标准时间进入夏季时间的英国来说,一天中有 23 个小时,夏季有 25 个小时回到格林威治标准时间。

我还没有在 nodatime 中发现任何可以直接执行此操作的内容

我可以在 NodaTime 中执行以下操作,但有没有更好的方法

DateTimeZone london = DateTimeZoneProviders.Tzdb["Europe/London"];
LocalDate start = new LocalDate(2021,3,28);
LocalDate end = new LocalDate(2021,29);

zoneddatetime startZ = london.AtStartOfDay(start);
zoneddatetime endZ = london.AtStartOfDay(end);
zoneddatetime dt = startZ;

int period = 1;

while (dt.ToInstant() < endZ.ToInstant())
{
    testOutputHelper.WriteLine("Period: " + period + "," + dt.ToString() + ",Hour: " + dt.Hour);
    
    dt = dt.PlusHours(1);
    period++;
}

解决方法

是的,你绝对可以在野田时间更简单地做到这一点:

public static Duration GetDayDuration(LocalDate date,DateTimeZone zone)
{
    var start = zone.AtStartOfDay(date);
    var end = zone.AtStartOfDay(date.PlusDays(1));
    return end - start;
}

这将返回一个 Duration,它是“经过的时间量”的 Noda Time 表示。您可以使用其中的 TotalHours 属性。 (使用 Hours 是错误的,因为 25 小时的持续时间会为 Hours 属性返回 1。)

完整示例:

using NodaTime;
using System;

class Test
{
    static void Main()
    {
        DateTimeZone london = DateTimeZoneProviders.Tzdb["Europe/London"];
        ShowDayDuration(new LocalDate(2021,3,28),london);
        ShowDayDuration(new LocalDate(2021,6,19),10,31),london);
    }
    
    public static void ShowDayDuration(LocalDate date,DateTimeZone zone)
    {
        var duration = GetDayDuration(date,zone);
        // Note: this truncation will give the result in rare cases,// when the UTC offset changes by a fractional number of hours.
        int hours = (int) duration.TotalHours;
        Console.WriteLine($"Duration of {date} in zone {zone.Id}: {hours} hours");
    }

    public static Duration GetDayDuration(LocalDate date,DateTimeZone zone)
    {
        var start = zone.AtStartOfDay(date);
        var end = zone.AtStartOfDay(date.PlusDays(1));
        return end.ToInstant() - start.ToInstant();
    }
}
,

Jon 的回答很棒,并展示了 Noda Time 如何使此类操作变得简单。

但是,由于该问题还询问了内置 API,为了完整起见,我将展示一种不需要 Noda Time 的替代方法。

using System;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
                    
public class Program
{
    public static void Main()
    {
        // Note,the following line is just an example for clarity.  If you know which form of identifier your platform supports
        // or are using TimeZoneConverter,or are using .NET 6+ (which will have conversions built-in),then you can just use the appropriate simple string.
        string tzid = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "GMT Standard Time" : "Europe/London";
        
        // Get the time zone and show a few different days and their duration.
        TimeZoneInfo zone = TimeZoneInfo.FindSystemTimeZoneById(tzid);
        ShowDayDuration(new DateTime(2021,zone);
        ShowDayDuration(new DateTime(2021,zone);
    }
    
    public static void ShowDayDuration(DateTime date,TimeZoneInfo zone)
    {
        TimeSpan duration = GetDayDuration(date,zone);
        Console.WriteLine($"Duration of {date:yyyy-MM-dd} in zone {zone.Id}: {duration.TotalHours} hours");
    }
    
    public static TimeSpan GetDayDuration(DateTime date,TimeZoneInfo zone)
    {
        // Just to make sure the input value is strictly a date with the time truncated.
        Debug.Assert(date.Kind == DateTimeKind.Unspecified);
        Debug.Assert(date.TimeOfDay == TimeSpan.Zero);
        
        // Subtract the start of the given date and the subsequent date.
        DateTimeOffset dto1 = GetStartOfDay(date,zone);
        DateTimeOffset dto2 = GetStartOfDay(date.AddDays(1),zone);
        return dto2 - dto1;
    }
    
    public static DateTimeOffset GetStartOfDay(DateTime date,TimeZoneInfo zone)
    {
        // Just to make sure the input value is strictly a date with the time truncated.
        Debug.Assert(date.Kind == DateTimeKind.Unspecified);
        Debug.Assert(date.TimeOfDay == TimeSpan.Zero);
        
        TimeSpan offset;        
        if (zone.IsAmbiguousTime(date))
        {
            // When the date/time is ambiguous,use the larger of the two offsets because the resulting value will come first sequentially.
            offset = zone.GetAmbiguousTimeOffsets(date).Max();
        }
        else
        {
            // When the date/time is invalid,find the next valid time.  Search by 15 minute increments to accomodate oddities of various time zones.
            while (zone.IsInvalidTime(date))
            {
                date = date.AddMinutes(15);
            }

            offset = zone.GetUtcOffset(date);
        }
        
        return new DateTimeOffset(date,offset);
    }
}

Working fiddle here.

输出:

Duration of 2021-03-28 in zone Europe/London: 23 hours
Duration of 2021-06-19 in zone Europe/London: 24 hours
Duration of 2021-10-31 in zone Europe/London: 25 hours

如您所见,Noda Time 的类型系统和内置 AtStartOfDay 方法使 Noda Time 成为一个更简单的选项,但仅使用内置类型仍然可以获得正确答案。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。