如何在 C# 中使用 DateTime.Now.Ticks 保持精度

Posted

技术标签:

【中文标题】如何在 C# 中使用 DateTime.Now.Ticks 保持精度【英文标题】:How to maintain precision using DateTime.Now.Ticks in C# 【发布时间】:2011-02-11 07:29:42 【问题描述】:

我知道当我在 C# 中使用 DateTime.Now.Ticks 时,它会返回一个 long 值,但我需要将它存储在一个 int 变量中,我很困惑我是否可以保持这种精度。到目前为止,我只有一个演员表

int timeStampValue = (int)DateTime.Now.Ticks;

这是一个项目限制,所以我知道有大量的精度损失。我想我只是想不出另一种方法来执行存储在 int 中的时间戳事情,然后我可以将其与其他时间戳进行比较。

如果可能的话,任何关于如何保持精度的建议或意见将不胜感激。

每个人的回答都是说明性的。实际上,我最终只是设置了一个涉及计数器的过程,当使用一个项目时,它的计数器设置为“0”,所有其他计数器都增加 1。然后,最高的计数器是下一个要使用的项目。

【问题讨论】:

为什么要存储在int中? 这是一个项目约束,这是我能想到的唯一方法,而且我过去不需要做时间戳的东西。 是不是根本不允许使用long,还是只用于存储到外部数据?例如,如果您可以使用 long 来获取数据,然后存储两个 int? 不允许使用long,我只能使用int 说你根本不能使用整数并没有真正给出限制。这是由于嵌入式系统吗?您在调用 '(int)DateTime.Now.Ticks;' 的那一刻使用 longs看看我下面的解决方案。您可以使用两个 uint 来表示整个时间戳 long 值,并为您可能需要做的任何数学创建自己的方法。这将允许您仅使用整数来获得完整分辨率。 【参考方案1】:

您需要所有最重要的位吗? (例如哪一年)

您需要所有最低有效位吗? (例如亚纳秒精度)

您需要测量多长时间的间隔?

如果您只需要毫秒精度,为什么不丢失最低有效位

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

编辑

OP 想要存储最近使用的项目的时间:如果这是单个用户的用户选择,您可能不想要任何短于一秒的内容!因为每秒有 10^7 个滴答声,所以 long 值中有 log(10^7)/log(2)=23 多余的位!

那么您需要多少空间?好吧,您的值应该指定年、月、日、小时、分钟和秒;一年大约有 3200 万秒 = 大约 24 位。如果要存储最近 10 年的价值,请添加 3 位。所以很容易适应 int32。 我建议

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

【讨论】:

我需要能够跟踪数组中最近最少使用的项目。【参考方案2】:

DateTime.Now 并不是那么精确。

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

话虽如此,如果您将值转换为较小的类型,默认情况下您可能会在任何情况下丢失数据。

考虑这个输出:

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

如何将其转换为 int 是一个现实的选择?

【讨论】:

是的,虽然我真的别无选择,但这并不是一个现实的选择,这只是我想到的第一个想法【参考方案3】:

如果一毫秒的分辨率足够好,您可以将一些基本DataTime 的偏移量存储在您的int 字段中,然后在需要时重建一个完整的DateTime。以 32 位整数存储的毫秒数将允许您的应用程序在包装之前运行 49 天。这是一个您可以使用的简单助手类:

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);
    

可以这样使用:

public static void Method()

    var offsetManager = new TimeOffsetManager();

    int offset = offsetManager.GetOffset();

    // ...

    DateTime realTime = offsetManager.OffsetToDateTime(offset);

【讨论】:

【参考方案4】:

比什么都重要...如果您死心塌地使用整数来存储您的 DateTime 并保持精度,您可以定义自己的结构,其中包含两个整数,每个包含 4 个字节,以及一个共享这些整数的 DateTime字节。

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);
    

【讨论】:

【参考方案5】:

参考我上面的评论。究竟是什么约束?如果限制是您不能将数据存储在 64 位变量中,那么如何按照以下方式进行操作。

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

现在您可以将 tsLow 和 tsHigh 都存储到您的外部数据中。您还可以实现特殊函数,使用两个单独的 32 位数字计算值来进行您自己的 64 位数学运算。

这实际上取决于您的实际限制。了解这些将有助于提出更好的解决方案。

【讨论】:

以上是关于如何在 C# 中使用 DateTime.Now.Ticks 保持精度的主要内容,如果未能解决你的问题,请参考以下文章

Django—— 模板层:变量过滤器标签自定义标签和过滤器

如何在 C# 的泛型中使用扩展

如何在网站项目中使用 C# 7? [复制]

如何在 C# 中使用 libcinder?

如何在 C# 中使用 imageMagick

我如何在 webBrowser 中使用 c# 执行点击事件