Unix Time - наносекунды? - PullRequest
       2

Unix Time - наносекунды?

2 голосов
/ 23 ноября 2011

Я использую этот метод (C #) для получения времени Unix в миллисекундах:

long UnixTime()
{
    return (long) (DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0)).TotalMilliseconds;
}   

Вопрос - Есть ли способ получить время Unix в наносекундах ?

Заранее спасибо.

Ответы [ 4 ]

4 голосов
/ 23 ноября 2011

Сам по себе расчет не сложен:

long UnixTime()
{
    DateTime epochStart=new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
    return (DateTime.UtcNow - epochStart).Ticks*100;
}

DateTime и TimeSpan внутренне хранят целое количество тиков, при этом один тик равен 100 нс. Я также указал начало эпохи как время UTC, потому что считаю уродливым вычитать DateTime s с разными Kind, даже если это работает.

Но DateTime.UtcNow имеет очень низкую точность. Он обновляется только каждые несколько миллисекунд (типичные значения варьируются от 1 мс до 16 мс).


Чтобы получить постоянную частоту кадров, вы можете использовать StopWatch, поскольку вам не нужно абсолютное время. Но если вы идете по этому пути, вы должны использовать напряженное ожидание. Поскольку Thread.Sleep, таймеры ... страдают от того же ограничения.

В качестве альтернативы вы можете использовать API timeBeginPeriod(1), чтобы заставить Windows обновлять часы и запускать таймеры каждые 1 мс. Но это глобальная настройка и увеличивает энергопотребление. Тем не менее, это лучше, чем заняты - подождите.

Для измерения разницы во времени вы можете использовать StopWatch с, основываясь на QueryPerformanceCounter, но это связано с собственным набором проблем, таких как рассинхронизация между различными ядрами. Я видел, что машины QueryPerformanceCounter перепрыгивали на несколько сотен миллисекунд, когда ваш поток был запланирован на другом ядре.

2 голосов
/ 23 ноября 2011

Свойство TotalMilliseconds возвращает double, содержащее целые и дробных миллисекунд.

Итак, вам нужно только умножить его значение на 1000000, чтобы получить наносекунды:

return (long) ((DateTime.UtcNow
    - new DateTime(1970, 1, 1, 0, 0, 0)).TotalMilliseconds * 1000000.0);
1 голос
/ 23 ноября 2011

Я думаю, что это не так просто (на обычном настольном компьютере x86) справиться с проблемами с точностью. Итак, в первую очередь класс DateTime в этой ситуации бесполезен. Вы можете использовать StopWatch

Вот очень хорошая статья об этом: http://www.codeproject.com/KB/testing/stopwatch-measure-precise.aspx

+ 1: https://stackoverflow.com/q/1416188/241506enter ссылка здесь

0 голосов
/ 23 ноября 2011

Этот класс поможет. Это позволяет вам конвертировать время от Unix до времени Windows. Комментарии могут не нуждаться в обновлении, но все работает хорошо.

public sealed class LinuxToWindowsFileTimeConverter : IValueConverter
    {
        static long ticksFrom1601To1970 = (long)(new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc) - DateTime.FromFileTimeUtc(0)).Ticks;        

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {                   
            return new DateTime();       
        }        

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return new DateTime();
        }


        public static DateTime Convert(Int64 nanoSecsSince1970)
        {            
            return Convert(nanoSecsSince1970, ScaleFactor.Billion);
        }

        /// <summary>
        /// Converts from Linux seconds to Windows DateTime
        /// </summary>
        /// <param name="secs"></param><remarks> secs</remarks>
        /// <param name="sf"></param><remarks>specifies scale factor.  
        /// Specify ScaleFactor.One for secs since 1970.  
        /// ScaleFactor.Thousand for milli (10^3) seconds since 1970. 
        /// ScaleFactor.Million for micro (10^6)seconds since 1970.
        /// ScaleFactor.Billion for nano (10^9)seconds since 1970.
        /// etc.</remarks>
        /// <returns></returns>
        public static DateTime Convert(Int64 secs, ScaleFactor sf)
        {                                                                   
            long hndrdnsfrom1601 = 0;

            switch(sf)
            {                
                case ScaleFactor.Billion:
                    hndrdnsfrom1601 = ticksFrom1601To1970 + secs / 100;                    
                    break;                
                default:
                    // TODO:  Correct for other cases.
                    hndrdnsfrom1601 = (long)ticksFrom1601To1970 + (secs * (long)ScaleFactor.TenMillion / (long)sf); 
                    break;
            }

            return DateTime.FromFileTimeUtc(hndrdnsfrom1601);                        
        }

        public static long ConvertBack(DateTime dateTimeInUTC)
        {
            if (dateTimeInUTC == new DateTime()) 
                dateTimeInUTC = new DateTime(1980, 1,1).ToUniversalTime();           

            long secsSince1970 = (dateTimeInUTC.ToFileTimeUtc() - ticksFrom1601To1970) * ((long)ScaleFactor.Billion / (long)ScaleFactor.TenMillion);           
            return secsSince1970;
        }        

        public Int64 ConvertBack(DateTime dateTimeInUTC, CultureInfo culture)
        {
            return ConvertBack(dateTimeInUTC, culture, ScaleFactor.Billion);
        }


        /// <summary>
        /// Converts from Windows file time to Linux seconds.
        /// </summary>
        /// <param name="dateTimeInUTC"></param>
        /// <param name="culture"></param>
        /// <param name="sf"></param><remarks>
        /// Specify ScaleFactor.One for secs since 1970.  
        /// ScaleFactor.Thousand for milli (10^3) seconds since 1970. 
        /// ScaleFactor.Million for micro (10^6)seconds since 1970.
        /// ScaleFactor.Billion for nano (10^9)seconds since 1970.
        /// </remarks>
        /// <returns></returns>
        public Int64 ConvertBack(DateTime dateTimeInUTC, CultureInfo culture, ScaleFactor sf)
        {
            long secsSince1970 = (dateTimeInUTC.ToFileTimeUtc() - ticksFrom1601To1970) * ((long)sf / (long)ScaleFactor.TenMillion);
            return secsSince1970;
        }
    }

    public enum ScaleFactor : long
    { 
        One = 1,
        Ten = 10,
        Hundred = 100,
        Thousand = 1000,
        TenThou = 10000,
        HundredThou = 100000,
        Million = 1000000,
        TenMillion = 10000000,
        HundredMillion = 100000000,
        Billion = 1000000000,
        TenBillion = 10000000000,
        HundredBillion = 100000000000
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...