Date Time Struct to deal with different time zones - c#

I make struct name DateTimeZone , I set it to take the UTC time and I get it to take local time.
DateTimeZone time = DateTime.Now;//time will equal the UTC time
DateTime localTime= time; // local time will equal the Local time
the struct
public struct DateTimeZone
{
private DateTime dateTime;
// public DateTimeZone Value { get; }
public static implicit operator DateTimeZone(DateTime value)
{
return new DateTimeZone() { dateTime = value.ToUniversalTime() };
}
public static implicit operator DateTime(DateTimeZone value)
{
return value.dateTime.ToLocalTime();
}
}
My question : is there easiest way to implement this than struct?
and this struct have exception when i save in DB cause entity frame work,
so I need to make mapping every time I use struct , How I can make mapping in concise manner?

A few things:
Be careful with your naming. An object with a name like DateTimeZone would be expected to contain either 1) time zone information only, or 2) a date and time and time zone. Your object is only an encapsulation wrapper around DateTime, so it is neither of these things.
Implicit operations can be evil - especially if they change the meaning of the value you're working with. I don't recommend using them with date/time, unless you really know what you're doing. It will quickly become confusing to any user of this object as to what value you were actually working with.
The ToUniversalTime and ToLocalTime functions change their behavior based on the DateTimeKind assigned to the .Kind property of the DateTime objects you're working with. You seem to be creating an API in which DateTime is always local and DateTimeZone is always UTC, but DateTimeKind will get in the way of this idea.
As mentioned in comments, you might look into using Noda Time, which is a very solid and well-thought-out API. In Noda Time, the Instant type always represents UTC, and the LocalDateTime type always represents a timezoneless date and time. Time zones are represented by DateTimeZone (see the conflict with your name), and the ZonedDateTime type combines these, such that you have both instant-in-time information, local-time information, and the associated time zone.
You mentioned Entity Framework. Unfortunately, EF will not work directly with either your custom object, or with Noda Time. It does not have the ability to do simple type conversions. This has been requested, but not yet implemented. You can follow the work item for it here. A workaround you can use is "buddy properties", as described here. They're not fun, but they work. Mostly.
You may find it reasonable to just use DateTime, and call methods like ToUniversalTime or ToLocalTime manually, when needed. If you want EF to properly set DateTimeKind when loading from the database, see this answer.
Keep in mind that both ToUniversalTime and ToLocalTime work with the computer's local time zone where the code happens to be running. This works fine for desktop and mobile applications, but is rarely desired for web applications, because changing the time zone of the server could drastically affect the data. Consider instead working with a named time zone via the built-in TimeZoneInfo class, or with the DateTimeZone class in Noda Time.
Additional reading for you:
Daylight saving time and time zone best practices
The timezone tag wiki

Maybe you should try this one:
public struct DateTimeZone
{
public DateTime DateTime;
public static explicit operator DateTimeZone(DateTime dt)
{
return new DateTimeZone { DateTime = dt.ToUniversalTime() };
}
}
var time = (DateTimeZone)DateTime.Now;
var localTime = time.DateTime;

Related

NodaTime: Replicating DateTime.Today

My service requests data from an external service that needs an argument for a particular date (doesn't need time information).
Until now, I've been using DateTime.Today (e.g. 10/24/2014 12:00:00).
I've moved to using NodaTime for improved testability but not sure of the best way to replicate this functionality:
public class SomeClass(IClock clock)
{
_clock = clock; //Injected at runtime, provides mockable interface
var localNow = _clock.Now.InZone(_serverTimeZone);
var today = localNow.ToDateTimeUnspecified().Date; //This close enough? Seems kinda long
}
To represent a date, you should use LocalDate rather than DateTime, ideally. So you want:
var localNow = clock.Now.InZone(serverZone);
var today = localNow.Date;
If you must use DateTime, then your current code is fine.
In Noda Time 2.0, this will be simpler due to a ZonedClock which is basically a composite of a clock and a time zone, allowing you to write:
// Or whatever...
private readonly ZonedClock zonedClock = clock.InZone(zone);
// Then later
LocalDate date = zonedClock.GetCurrentDate();
Noda Time 2.0 isn't ready for release yet, but I wanted to give you an idea of what's coming.

ensure that utc datetime is persisted

Let us say I have a situation where I set the creation UTC date time just before I persist the entity. Usually, I would do it like this:
var something = new Something;
something.CreationDT = DateTime.UtcNow;
repo.Save(something);
What is the best way to ensure that this always happens. I know how to create a DateTime wrapper for testing purposes but this would not necessary help me here as programmers could still use:
something.CreationDT = DateTime.Now;
Is there a pattern to ensure that every programmer uses UTC?
If you always want to force the UTC date on the object and this is the exact code, then just do it as part of the constructor e.g.
public Something()
{
CreatedDT = DateTime.UtcNow;
}
public DateTime CreatedDT { get; private set; }
...
Save(new Something());
Obviously this doesn't cater for scenarios where you create the object earlier in the application and persist later, however, that doesn't appear to be the case here.
I would definitely avoid allowing users to set Now whilst internally returning UtcNow, that's just going to confuse people. If anything use UtcNow is better as it's more readable for the developer - it's clear to see that the value has to be UTC.
For this sort of thing, I generally try to let the DB do as much work as possible so I would have a default value set to the current UTC date/time so I don't need to worry about sending it from my client at all.

Instant.Now for NodaTime

I'm trying to get a handle on using the Noda Time framework by Jon Skeet (and others).
I'm trying to store the current now(Instant). Instant is created from a long ticks, but what is the current now count of Ticks?
Is it:
Instant now = new Instant(DateTime.Now.ToUniversalTime().Ticks);
And or?
Instant now = Instant.FromDateTimeUtc(DateTime.Now.ToUniversalTime());
Are they equivalent, am I even doing this right?
PS, if Jon answer's this - I'd like to propose an Instant.Now property.
PS2 I know the title contains a tag, but it wouldn't let me have a short "Instant.Now" title.
I did a bit of research and it seems that the NodaTime way is to get the now moment according to a clock.
If you want to get the current time using the system clock, just use SystemClock.Instance.GetCurrentInstant().
However, instead of using the SystemClock.Instance directly in your code, it's preferable that you inject an IClock dependency in your time-aware classes.
This will allow you to:
provide the class with SystemClock.Instance at runtime, so the code will use the correct time
supply a fake implementation of IClock during unit testing to allow you to tweak the time as needed in order to test various scenarios (like the passing of time). There's a NodaTime.Testing project that offers such a class, called FakeClock.
I find this very useful. I think having something like new Instant() or Instant.Now return the current time would make it easier to hardcode usages of SystemClock under the covers, therefore missing the testing advantage that NodaTime offers.
For more info on unit testing with NodaTime, see this link.
Regarding your code examples: they are not equivalent.
Instant.FromDateTimeUtc(DateTime.Now.ToUniversalTime()) will indeed give you the current instant in UTC.
new Instant(DateTime.Now.ToUniversalTime().Ticks) will give you a wrong date far in the future, because the BCL's DateTime.Ticks represents the number of ticks since 1/1/0001, and NodaTime's Instant.Ticks represents the number of ticks since 1/1/1970 (see the remark here).
SystemClock.Now returns the current time as an Instant value:
Instant now = SystemClock.Instance.Now;
But you may want to heed the remarks in the documentation for the IClock interface:
IClock is intended for use anywhere you need to have access to the current time. Although it's not strictly incorrect to call SystemClock.Instance.Now directly, in the same way as you might call UtcNow, it's strongly discouraged as a matter of style for production code. We recommend providing an instance of IClock to anything that needs it, which allows you to write tests using the stub clock in the NodaTime.Testing assembly (or your own implementation).
As a simple example, suppose you have a Logger class that needs the current time. Instead of accessing SystemClock directly, use an IClock instance that's supplied via its constructor:
public class Logger
{
private readonly IClock clock;
public Logger(IClock clock)
{
this.clock = clock;
}
public void Log(string message)
{
Instant timestamp = this.clock.Now;
// Now log the message with the timestamp...
}
}
When you instantiate a Logger in your production code, you can give it SystemClock.Instance. But in a unit test for the Logger class, you can give it a FakeClock.

.Net DateTime Precision

within my .net domain object I am tracking each state transition. This is done by putting the state set into a state history collection. So later on, one can see an desc ordered list to find out which state was changed at what time.
So there is a method like this:
private void SetState(RequestState state)
{
var stateHistoryItem = new RequestStateHistoryItem(state, this);
stateHistoryItems.Add(stateHistoryItem);
}
When a new RequestStateHistoryItem is instantiated, the current date is automatically assigned. Like this:
protected IdentificationRequestStateHistoryItem()
{
timestamp = EntityTimestamp.New();
}
The EntityTimestamp object is an object containing the appropiate user and created and changed date.
When listing the state history, I do a descending order with Linq:
public virtual IEnumerable<RequestStateHistoryItem> StateHistoryItems
{
get { return stateHistoryItems.OrderByDescending(s => s.Timestamp.CreatedOn.Ticks); }
}
Now when a new Request is instantiated the first state Received is set in the constructor SetState(RequestState.Received). Then, without any delay and depending on some conditions, a new state Started is set. After some time (db operations) the state Finished is set.
Now when performing the descending ordering, the Received always is AFTER the Started state. When I am debugging slowly, or when putting a System.Threading.Thread.Sleep(1000) before setting the state to Started, the ordering works.
If not, as told above, the Started state's CreatedOn is OLDER then the Received CreatedOn date?!
TimeOfDay {17:04:42.9430318} FINSHED
Ticks 634019366829430318
TimeOfDay {17:04:39.5376207} RECEICED
Ticks 634019366795376207
TimeOfDay {17:04:39.5367815} STARTED
Ticks 634019366795367815
How can that be? I would understand if the received and start date is exactly the same, but I don't understand how it can even be BEFORE the other one?
I already tried new DateTimePrecise().Now, (see DateTimePrecise class) I found in another question. Same result.
Anyone knows what that could be?
Update
public virtual bool Finish()
{
// when I put the SetState(State.Received) from the constructor into here, the timestamp of finish still is BEFORE received
SetState(IdentificationRequestState.Received);
SetState(IdentificationRequestState.Finished);
// when I put the SetState(State.Received) after Finished, then the Received timestamp is BEFORE Finished
SetState(IdentificationRequestState.Finished);
SetState(IdentificationRequestState.Received);
var match = ...
if (match != null)
{
...
}
else
{
...
}
}
DateTime.Now is not accurate to the millisecond. It is only updated at larger intervals, something like 30 or 15 milliseconds (which is just the way Window's internal clock works, IIRC).
System.Diagnostics.Stopwatch is a more accurate way to measure time differences. It also doesn't have the overhead of UTC to local time conversions etc. The DateTimePrecise class uses a combination of DateTime and Stopwatch to give a more accurate time than DateTime.Now does.
You are retrieving the timestamp at an undetermined time before you add it to your collection.
The delay between retrieving it and adding it to the collection is variable - for example your thread may be pre-empted by the scheduler after getting the timestamp and before adding to the collection.
If you want strict ordering, you need to use synchronisation, something like the following every time you instantiate a history item:
lock(syncLock)
{
// Timestamp is generated here...
var stateHistoryItem = new RequestStateHistoryItem(state, this);
// ... but an indeterminate time can pass before ...
...
// ... it's added to the collection here.
stateHistoryItems.Add(stateHistoryItem);
}
Have you tried setting both the Received and Started timestamps via the same approach (i.e. moving the Received stamp out of the constructor and setting it via property or method to match how the Started status is set?).
I know it doesn't explain why, but constructors are somewhat special in the runtime. .NET constructors are designed to execute as fast as possible, so it wouldn't surprise me that there are some side-effects of the focus on performance.

Best way to compute UTC/local datetime conversion in a WCF client/server application

I've got a client/server application, written in WCF / C#3.5.
The server is in my local TimeZone, and clients are spreaded accross the world.
My current strategy is to use UTC DateTime everywhere on the server and in the database, and to let the clients handle correctly the UTC DateTimes they receive.
This means that everytime the client receives a message, its first task is to convert the DateTimes contained in the message from UTC to Local.
I've defined an interface, implemented by all my [DataContract] objects to help this task :
public interface IConvertToLocalTime {
void ConvertToLocalTime();
}
So I typically handle a message from the server this way :
public void ServerCallbackFoo(MyObject a, MyObject2 b)
{
a.ConvertToLocalTime();
b.ConvertToLocalTime();
// my business code goes there
}
This works fine, but I'm not very pleased with the fact that I've got to manually call the conversion method.
It seems to me that this task should be managed by the WCF framework. Am I missing something there? Is there a better way to automate the conversion ?
To my knowledge, WCF does not provide any kind of automation to aid time conversions, and personally, I wouldn't expect it to.
And I agree with you. Having to manually call the conversion routine is not the ideal. It doesn't "feel" elegant.
To me, a more elegant solution would be to "lazily" evaluate the DateTime as it is needed. Instead of providing a function that must be called to convert the UTC times to local times, put this logic inside each DateTime property's get function. That way, when the DateTime is retrieved from the object, it is automatically converted to local time.
I'm possibly not understanding the question, but wouldn't it be easier to use the built in DateTime.ToLocalTime and DateTime.ToUniversalTime as needed since you are using .NET for both the service and the client. You should be able to check the .Kind property to see if the DateTime is local or UTC.
DateTime test = DateTime.Now; //already local time
DateTime LocalTest = test.ToLocalTime();
DateTime UtcTest = test.ToUniversalTime();
You may also want to look at this SO Question regarding handling DateTime serialization.
You could make clients convert to/from local time precisely when presenting information to the user, and conversely do it first thing when reading user entered data. The rest of the client could then work with UTC.

Categories

Resources