开发者

How to maintain precision using DateTime.Now.Ticks in C#

I know that when I use DateTime.Now.Ticks in C# it returns a long value but I need to store it in an int variable and I am confused as to whether or not I can maintain that precision. As of right now I just have a cast

int timeStampVal开发者_开发知识库ue = (int)DateTime.Now.Ticks;

This is a project constraint so I understand there is tons of precision lost. I guess I just couldn't think of another way to do a timestamp thing stored in an int that I could then compare to other timestamps.

Any suggestions or advice on how to maintain the precision, if possible, would be much appreciated.

Everyone's answers were illustrative. I actually ended up just setting up a process involving counters where when an item is used it's counter is set to '0' and all other counters are incremented by 1. Then whatever is the highest counter is the next item to use.


Do you need all the most-significant bits? (e.g. which year)

Do you need all the least significant bits? (e.g. sub-nanosecond precision)

How long an interval do you need to measure over?

If you need millisecond precision only, why not lose the least significant bits

int timeStamp = (int)(DateTime.Now.Ticks >> 10) // lose smallest 10 bits

edit

the OP wants to store times of recently used items: if this is user selections for a single user, you probably don't want anything shorter than a second! as there are 10^7 ticks per second, there are log(10^7)/log(2)=23 excess bits in the long value!

So how much space do you need? Well, your values ought to specify year, month, day, hour, minute and second; There are about 32 million seconds in a year = about 24 bits. add 3 bits if you want to store the last 10 years worth. So will easily fit into an int32. I'd suggest

int timeStamp = (int)(DateTime.Now.Ticks >>23) // retain bits 23 to 55


DateTime.Now isn't all that precise.

http://blogs.msdn.com/ericlippert/archive/2010/04/08/precision-and-accuracy-of-datetime.aspx

With that said, if you're casting the value down to a smaller type, by default you can lose data in any situation.

Consider this output:

int.MaxValue:       2147483647
DateTime.Now.Ticks: 634075598514933010

How is casting that down to an int a realistic option?


If a resolution of a millisecond is good enough, you could store offsets from some base DataTime in your int field and then reconstruct a full DateTime when you need it. Milliseconds stored in a 32-bit integer would allow your application to run for 49 days before it wrapped. Here is a simple helper class you could use:

public class TimeOffsetManager
{
    public TimeOffsetManager()
    {
        InitialDateTime = DateTime.Now;
    }

    public DateTime InitialDateTime { get; private set; }

    public int GetOffset()
    {
        TimeSpan elapsed = DateTime.Now - InitialDateTime;
        return (int)Math.Round(elapsed.TotalMilliseconds);
    }

    public DateTime OffsetToDateTime(int offset)
    {
        return InitialDateTime + TimeSpan.FromMilliseconds(offset);
    }
}

It can be used like:

public static void Method()
{
    var offsetManager = new TimeOffsetManager();

    int offset = offsetManager.GetOffset();

    // ...

    DateTime realTime = offsetManager.OffsetToDateTime(offset);
}


More for kicks than anything... If you're dead set on using ints to store your DateTime and maintain precision, you could define your own struct that contains two ints, each containing 4 bytes, and a DateTime that shares those bytes.

public class Program
{
    public static void Main(string[] args)
    {
        DateTime now = DateTime.Now;
        var myDate = new Int32BackedDate(now.Ticks);

        Console.WriteLine(now);
        Console.WriteLine(myDate.Date);
    }
}

[StructLayout(LayoutKind.Explicit, Size = 8)]
public struct Int32BackedDate
{
    [FieldOffset(4)]
    private readonly int _high;

    [FieldOffset(0)]
    private readonly int _low;

    [FieldOffset(0)]
    private readonly DateTime _date;

    public DateTime Date { get { return _date; } }

    public Int32BackedDate(long ticks)
    {
        _date = default(DateTime);
        byte[] bytes = BitConverter.GetBytes(ticks);
        _low = BitConverter.ToInt32(bytes, 0);
        _high = BitConverter.ToInt32(bytes, 4);
    }
}


In reference to my comment above. What is the constraint exactly? If the constraint is that you cannot store the data in a 64 bit variable then how about doing something along the lines of.

uint tsLow = (uint)DateTime.Now.Ticks;
uint tsHigh = (uint)(DateTime.Now.Ticks >> 32);

Now you can store both the tsLow and tsHigh to your external data. You could also implement special functions that could calculate values using the two separate 32 bits numbers to do your own 64bit math.

This really depends on your actual constraints. Knowing those will help to suggest better solutions.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜