.NET Compact Framework中DateTime.Now的毫秒总是为零吗?

13

我想要在Windows Mobile项目的日志中添加一个时间戳。精确度必须至少达到百毫秒。

然而,我的调用DateTime.Now返回一个DateTime对象,其中Millisecond属性设置为零。同时,Ticks属性也相应地四舍五入了。

如何获得更好的时间精度?
请记住,我的代码运行在Compact Framework 3.5上。我使用HTC Touch Pro 2设备。

基于MusiGenesis的答案,我创建了以下类来解决这个问题:

/// <summary>
/// A more precisely implementation of some DateTime properties on mobile devices.
/// </summary>
/// <devdoc>Tested on a HTC Touch Pro2.</devdoc>
public static class DateTimePrecisely
{
    /// <summary>
    /// Remembers the start time when this model was created.
    /// </summary>
    private static DateTime _start = DateTime.Now;
    /// <summary>
    /// Remembers the system uptime ticks when this model was created. This
    /// serves as a more precise time provider as DateTime.Now can do.
    /// </summary>
    private static int _startTick = Environment.TickCount;

    /// <summary>
    /// Gets a DateTime object that is set exactly to the current date and time on this computer, expressed as the local time.
    /// </summary>
    /// <returns></returns>
    public static DateTime Now
    {
        get
        {
            return _start.AddMilliseconds(Environment.TickCount - _startTick);
        }
    }
}

2
不需要重新命名您的问题为“[已解决]”。您可以通过主页或搜索结果上的黄色答案计数器来确定问题是否有已接受的答案。 - spoulson
2
作为此类的来源,我应该提到,这个类返回的值几乎肯定会与常规的DateTime.Now有所偏差,可能在一天内多达几秒钟甚至更多。您可以通过设置类的_start属性,等待一段时间(一天或其他时间),并将DateTime.NowDateTimePrecisely.Now进行比较来轻松测试这一点。 - MusiGenesis
1
如果您发现漂移量不可接受,您可以添加一个“重置”方法,该方法获取_start_startTick的新值,并定期调用它。这将使其与系统时钟长期同步,同时仍然为您提供(据称)毫秒分辨率。或者使用ctacke的代码。 - MusiGenesis
1
是的,漂移高度依赖于OEM在硬件中如何处理时钟、使用的处理器和晶体。我见过糟糕的(每天近一分钟的漂移)和好的(每天10毫秒的漂移)。如果没有单独的RTC,那就很难完全消除它。 - ctacke
1
PC晶体通常很便宜(因此不太准确)。 - ctacke
显示剩余3条评论
4个回答

14

Environment.TickCount会返回自上次重启以来Windows(或Windows Mobile)已运行的毫秒数。

要使用它,请将这两个表单级变量添加到您的代码中:

private DateTime _start;
private int _startTick;
在你的表单的Load事件中,执行以下操作:
private void Form1_Load(object sender, EventArgs e)
{
    _start = DateTime.Now;
    _startTick = Environment.TickCount;
}

当您需要一个带毫秒的 DateTime 对象时,请执行以下操作:

DateTime timeStamp = 
    _start.AddMilliseconds(Environment.TickCount - _startTick);

Environment.TickCount 是一个 int 类型,其值在大约 25 天后会 "wrap around" 至 Int32.MinValue。如果您的设备需要长时间运行而无需重新启动,那么您需要添加一个检查,以检查当前的 Environment.TickCount 值是否小于上一次读取的值,如果是,则重置 _start_startTick


+1. 这个方法解决了问题。可惜微软(或HTC?)没有在他们的代码中使用这个方法。 - Marcel
3
这是HTC的失败,而不是微软的。提供操作系统的时间取决于原始设备制造商。 - ctacke
请帮帮我,因为我不知道它如何提供更准确的时间。你会有“更多数字”,但那只是因为起始时间已经不包含秒的分数部分,所以你只是添加“虚构”的数字。如果在日志中使用它,则可以看到记录条目之间的经过时间,但无法与其他系统时间进行比较。 - HoGo

2

+1 为你的提示点赞。然而,这已经超出了我的准确度(在积极意义上)。 - Marcel

1

主要的替代方案是System.Diagnostics.Stopwatch类。

它在CE中可用,但请注意IsHighResolution属性。它可能在您的设备上为False,但请检查。

这是您在没有P/Invoke的情况下可以获得的最准确的结果。


-3
在常规框架v2.0中,您可以使用DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")来获取毫秒。更多的f表示更高的精度。

不适用于CF。请参考该问题的其他答案。 - ctacke

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接