-
Notifications
You must be signed in to change notification settings - Fork 4.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Address the TimeProvider community feedback #84274
Comments
Tagging subscribers to this area: @dotnet/area-system-datetime Issue DetailsOriginal writing by @stephentoub
{
public override LocalTimeZone => local;
}
Change Proposalnamespace System
{
public abstract class TimeProvider
{
public static TimeProvider System { get; }
+ protected TimeProvider();
- public abstract DateTimeOffset UtcNow { get; }
+ public virtual DateTimeOffset GetUtcNow();
- public DateTimeOffset LocalNow { get; }
+ public DateTimeOffset GetLocalNow();
- public abstract TimeZoneInfo LocalTimeZone { get; }
+ public virtual TimeZoneInfo LocalTimeZone { get; }
- public abstract long GetTimestamp();
+ public virtual long GetTimestamp();
- protected TimeProvider(long timestampFrequency);
- public static TimeProvider FromLocalTimeZone(TimeZoneInfo timeZone);
- public long TimestampFrequency { get; }
+ public virtual long TimestampFrequency { get; } // or `public long TimestampFrequency { get; }` and `protected virtual long TimestampFrequencyCore { get; }`
- public abstract ITimer CreateTimer(TimerCallback callback, object? state, TimeSpan dueTime, TimeSpan period);
+ public virtual ITimer CreateTimer(TimerCallback callback, object? state, TimeSpan dueTime, TimeSpan period);
public TimeSpan GetElapsedTime(long startingTimestamp, long endingTimestamp);
}
}
|
namespace System;
public abstract class TimeProvider
{
public static TimeProvider System { get; }
+ protected TimeProvider();
- public abstract DateTimeOffset UtcNow { get; }
+ public virtual DateTimeOffset GetUtcNow();
- public DateTimeOffset LocalNow { get; }
+ public DateTimeOffset GetLocalNow();
- public abstract TimeZoneInfo LocalTimeZone { get; }
+ public virtual TimeZoneInfo LocalTimeZone { get; }
- public abstract long GetTimestamp();
+ public virtual long GetTimestamp();
- protected TimeProvider(long timestampFrequency);
- public static TimeProvider FromLocalTimeZone(TimeZoneInfo timeZone);
- public long TimestampFrequency { get; }
+ public virtual long TimestampFrequency { get; }
- public abstract ITimer CreateTimer(TimerCallback callback, object? state, TimeSpan dueTime, TimeSpan period);
+ public virtual ITimer CreateTimer(TimerCallback callback, object? state, TimeSpan dueTime, TimeSpan period);
public TimeSpan GetElapsedTime(long startingTimestamp, long endingTimestamp);
} |
It seems a bit odd to me to dismiss the case of a TimeProvider with a time zone other than that of the system as niche… F.ex. I'm hosting quite a few websites on Azure App Service where the server time zone is set to UTC and it'd be much simpler if I could just put the result of To avoid exposing a static factory, maybe the proposed LocalTimeProvider could also be included by default? |
Nit: in most cases the zone of the server process isn't relevant either, and you should be pulling the zone from a business record or profile data, even if you essentially have a "constant" zone. |
That's fair, but I'd like to point out that this doesn't mean that you can't get the current time with a different timezone, just that you need to translate it yourself, which matches what you'd do today: TimeZoneInfo tz = /*...*/;
DateTimeOffset staticWay = TimeZoneInfo.ConvertTime(DateTimeOffset.Now, tz);
DateTimeOffset timeProviderWay = TimeZoneInfo.ConvertTime(timeProvider.GetLocalNow(), tz); If we believe this is a common enough problem, we can bring back a static factory.
From my point of view, I'd rather have one more method than exposing another type.
Agreed. I would think that the server mostly deals with UTC. Aren't most cloud machines configured to have UTC as their local time zone? My understanding is that time zone is mostly a client thing; data should be stored in UTC and converted on the client. There are of course exceptions, like a calendar application might allow appointments to be configured to be for a certain time zone. But even in that case I'd think the date fields would be stored as UTC and the time zone be stored as a separate field. |
Note that I'm actually arguing for this method, but arguing against using it at server start-time DI. You potentially want to use it in request time DI, as part of entity hydration (for example when user records are hydrated to provide roles, etc).
Servers being set to UTC is a "solution domain" problem - that is, you set it to UTC because it has to be set to something, but pedantically the fact that it's in a "timezone" should be irrelevant in the first place. Some cloud services do allow you to set a timezone, which might be required in some cases - the most relevant example I've seen is for Azure FaaS, with a scheduled trigger.
This is false and true. Storing in UTC is a "solution domain" issue, in that you don't actually care about UTC at all, it's just what most platforms/languages provide to you. The more relevant type is equivalent to the Java Yes, you would convert on the client. That said, you have two potential timezones to consider:
Although some people argue for this, I'm in agreement with Jon Skeet's views on this, which advocates for storing local time, due to problems with updating timezone rules. |
#36617
Original writing by @stephentoub
Delete FromLocalTimeZone. This is such a niche use case, it’s not worth cluttering up the surface area of the type for or breeding choice when someone does TimeProvider. in an IDE, e.g. I don’t want someone accidentally thinking they should be doing TimeProvider.FromLocalTimeZone(TimeZoneInfo.Local) or something like that. For someone who does have this scenario, once the system implementation is the base, they can achieve it with their own simple derived type:
sealed class LocalTimeProvider(TimeZoneInfo local) : TimeProvider
What’s currently checked in is:
Change Proposal
The text was updated successfully, but these errors were encountered: