Question

What is the idiomatic way to get the system's time as a LocalDateTime in Noda Time? The most direct method I could think of would be

var dt = DateTime.Now
LocalDateTime systemTime = new LocalDateTime(dt.Year, dt.Month, dt.Day, dt.Hour, dt.Minute);

but given that Noda Time's entire purpose is to replace DateTime with something that has nicer semantics, I assumed there was a preferred method than to use DateTime in the above manner. The best I could come up with using Noda's facilities is

var zone = NodaTime.TimeZones.BclDateTimeZone.ForSystemDefault();
LocalDateTime systemTime = SystemClock.Instance.Now.InZone(zone).LocalDateTime;

but this seems quite verbose.

Was it helpful?

Solution

Your second example is exactly how you would do this. It is intentionally verbose. See Noda Time's design philosophy.

Think of it in three parts:

  1. Get the current moment in time:

    // Instant now = SystemClock.Instance.Now;               // NodaTime 1.x
    Instant now = SystemClock.Instance.GetCurrentInstant();  // NodaTime 2.x
    
  2. Get the system's time zone. (This is the preferred syntax)

    DateTimeZone tz = DateTimeZoneProviders.Bcl.GetSystemDefault();
    
  3. Apply the time zone to the instant:

    ZonedDateTime zdt = now.InZone(tz);
    

Your last step of getting a LocalDateTime is trivial, but recognize that when you do it, you are stripping away any time zone information. "Local" in NodaTime does not mean "local to the computer where the code is running". (In other words, it's not like DateTimeKind.Local)

Additional things to think about:

  • You may prefer to abstract the clock using the IClock interface:

    IClock clock = SystemClock.Instance;
    // Instant now = clock.Now;               // NodaTime 1.x
    Instant now = clock.GetCurrentInstant();  // NodaTime 2.x
    

    Then you could pass the clock in as a method parameter, or inject it with your favorite DI/IoC framework. (Autofac, Ninject, StructureMap, whatever...). The advantage is then you could use a NodaTime.Testing.FakeClock during your unit tests. See Unit Testing with Noda Time for more details.

  • You might also prefer to pass in the DateTimeZone so you can run your code anywhere without being tied to the system time zone. This is important for server applications, but less so for desktop/mobile apps.

  • If you have other work that's using IANA time zones, or if you're using the .NET Standard build of Noda Time, then change step 2 to use the Tzdb provider:

    DateTimeZone tz = DateTimeZoneProviders.Tzdb.GetSystemDefault();
    

    The TZDB zones are much more accurate than the BCL zones. Noda Time will map your system's Windows (BCL) time zone to an IANA (TZDB) time zone in this initial call.

If you have curiosity into why DateTime.Now is so compact while Noda Time is so verbose, try decompiling DateTime.Now or looking at the MS reference sources. You'll see that it's doing essentially the same steps under the hood.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top