none
A more Efficient DateTime.Now ,similar to UtcNow RRS feed

  • General discussion

  • the idea is similar to the UtcNow implementation which is very high perfomant ,

    and the performance is between X2 to X5 faster then the regular .net DateTime.Now

    it usually takes 4 ticks instead of 20

    it uses FileTimeToLocalFileTime()

    the only problem is that it needs to use the private DateTime(Uint64) ctor , which sets directly the uint64 dataData

    this is the property code:

            public static DateTime Now
            {
                get
                {
                    long systemTime;
                    GetSystemTimeAsFileTime(out systemTime);
                    long localTime;
                    FileTimeToLocalFileTime(ref systemTime, out localTime);

                    return new DateTime(((UInt64) (localTime + FileTimeOffset)) | KindUtc);
                }
            }

     

    this is the regular .net DateTime.Now:

            public static DateTime Now {
                get {

                    return TimeZone.CurrentTimeZone.ToLocalTime(UtcNow);
                }
            }

    the performance problem of datetime.now happens because of the ToLocalTime function

     

    but the native api already has a function the does that more efficiently

     

    anyway i think that the private ctor and dateDate should be exposed in order to save and instantiate DateTime faster from the dateData

     

    so here is the full working class of DateTime (you can copy & paste it in vs to see it better) :

     

        [StructLayout(LayoutKind.Auto)]
        [Serializable]
        public struct DateTime
        {
            //// Number of 100ns ticks per time unit
            private const long TicksPerMillisecond = 10000;
            private const long TicksPerSecond = TicksPerMillisecond*1000;
            private const long TicksPerMinute = TicksPerSecond*60;
            private const long TicksPerHour = TicksPerMinute*60;
            private const long TicksPerDay = TicksPerHour*24;

            //// Number of days in a non-leap year
            private const int DaysPerYear = 365;
            //// Number of days in 4 years
            private const int DaysPer4Years = DaysPerYear*4 + 1;
            //// Number of days in 100 years
            private const int DaysPer100Years = DaysPer4Years*25 - 1;
            //// Number of days in 400 years
            private const int DaysPer400Years = DaysPer100Years*4 + 1;

            private const long FileTimeOffset = (DaysPer400Years * 4) * TicksPerDay;

            private const int DatePartYear = 0;
            private const int DatePartDayOfYear = 1;
            private const int DatePartMonth = 2;
            private const int DatePartDay = 3;

            private static readonly int[] DaysToMonth365 = {
                                                               0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365
                                                           };

            private static readonly int[] DaysToMonth366 = {
                                                               0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366
                                                           };

            private const UInt64 TicksMask = 0x3FFFFFFFFFFFFFFF;
            private const UInt64 KindUtc = 0x4000000000000000;

            // The data is stored as an unsigned 64-bit integeter
            //   Bits 01-62: The value of 100-nanosecond ticks where 0 represents 1/1/0001 12:00am, up until the value
            //               12/31/9999 23:59:59.9999999
            //   Bits 63-64: A four-state value that describes the DateTimeKind value of the date time, with a 2nd
            //               value for the rare case where the date time is local, but is in an overlapped daylight
            //               savings time hour and it is in daylight savings time. This allows distinction of these
            //               otherwise ambiguous local times and prevents data loss when round tripping from Local to
            //               UTC time.
            private readonly UInt64 dateData;


            private DateTime(UInt64 dateData)
            {
                this.dateData = dateData;
            }


            private Int64 InternalTicks
            {
                get { return (Int64) (dateData & TicksMask); }
            }


            // Checks if this DateTime is equal to a given object. Returns
            // true if the given object is a boxed DateTime and its value
            // is equal to the value of this DateTime. Returns false
            // otherwise.
            //
            public override bool Equals(Object value)
            {
                if (value is DateTime)
                {
                    return InternalTicks == ((DateTime) value).InternalTicks;
                }
                return false;
            }

            public bool Equals(DateTime value)
            {
                return InternalTicks == value.InternalTicks;
            }

            // Returns the day-of-month part of this DateTime. The returned
            // value is an integer between 1 and 31.
            //
            public int Day
            {
                get { return GetDatePart(DatePartDay); }
            }

            public int Millisecond
            {
                get { return (int) ((InternalTicks/TicksPerMillisecond)%1000); }
            }

            // Returns the minute part of this DateTime. The returned value is
            // an integer between 0 and 59.
            //
            public int Minute
            {
                get { return (int) ((InternalTicks/TicksPerMinute)%60); }
            }

            // Returns the month part of this DateTime. The returned value is an
            // integer between 1 and 12.
            //
            public int Month
            {
                get { return GetDatePart(DatePartMonth); }
            }

            // Returns a DateTime representing the current date and time. The
            // resolution of the returned value depends on the system timer. For
            // Windows NT 3.5 and later the timer resolution is approximately 10ms,
            // for Windows NT 3.1 it is approximately 16ms, and for Windows 95 and 98
            // it is approximately 55ms.
            //
            public static DateTime Now
            {
                get
                {
                    long systemTime;
                    GetSystemTimeAsFileTime(out systemTime);
                    long localTime;
                    FileTimeToLocalFileTime(ref systemTime, out localTime);

                    return new DateTime(((UInt64) (localTime + FileTimeOffset)) | KindUtc);
                }
            }

            public static DateTime UtcNow
            {
                get
                {
                    // following code is tuned for speed. Don't change it without running benchmark.
                    long ticks;
                    GetSystemTimeAsFileTime(out ticks);
                    return new DateTime(((UInt64) (ticks + FileTimeOffset)) | KindUtc);
                }
            }

            // Returns the hash code for this DateTime.
            //
            public override int GetHashCode()
            {
                Int64 ticks = InternalTicks;
                return unchecked((int) ticks) ^ (int) (ticks >> 32);
            }

            // Returns the hour part of this DateTime. The returned value is an
            // integer between 0 and 23.
            //
            public int Hour
            {
                get { return (int) ((InternalTicks/TicksPerHour)%24); }
            }

            // Returns the second part of this DateTime. The returned value is
            // an integer between 0 and 59.
            //
            public int Second
            {
                get { return (int) ((InternalTicks/TicksPerSecond)%60); }
            }

            // Returns the tick count for this DateTime. The returned value is
            // the number of 100-nanosecond intervals that have elapsed since 1/1/0001
            // 12:00am.
            //
            public long Ticks
            {
                get { return InternalTicks; }
            }

            // Returns the time-of-day part of this DateTime. The returned value
            // is a TimeSpan that indicates the time elapsed since midnight.
            //
            public TimeSpan TimeOfDay
            {
                get { return new TimeSpan(InternalTicks%TicksPerDay); }
            }


            // Returns the year part of this DateTime. The returned value is an
            // integer between 1 and 9999.
            //
            public int Year
            {
                get { return GetDatePart(DatePartYear); }
            }

            public override String ToString()
            {
                return Day+"/"+Month+"/"+Year+" "+Hour+":"+Minute+":"+Second+"."+Millisecond;
            }

            // Returns a given date part of this DateTime. This method is used
            // to compute the year, day-of-year, month, or day part.
            private int GetDatePart(int part)
            {
                Int64 ticks = InternalTicks;
                // n = number of days since 1/1/0001
                var n = (int) (ticks/TicksPerDay);
                // y400 = number of whole 400-year periods since 1/1/0001
                int y400 = n/DaysPer400Years;
                // n = day number within 400-year period
                n -= y400*DaysPer400Years;
                // y100 = number of whole 100-year periods within 400-year period
                int y100 = n/DaysPer100Years;
                // Last 100-year period has an extra day, so decrement result if 4
                if (y100 == 4) y100 = 3;
                // n = day number within 100-year period
                n -= y100*DaysPer100Years;
                // y4 = number of whole 4-year periods within 100-year period
                int y4 = n/DaysPer4Years;
                // n = day number within 4-year period
                n -= y4*DaysPer4Years;
                // y1 = number of whole years within 4-year period
                int y1 = n/DaysPerYear;
                // Last year has an extra day, so decrement result if 4
                if (y1 == 4) y1 = 3;
                // If year was requested, compute and return it
                if (part == DatePartYear)
                {
                    return y400*400 + y100*100 + y4*4 + y1 + 1;
                }
                // n = day number within year
                n -= y1*DaysPerYear;
                // If day-of-year was requested, return it
                if (part == DatePartDayOfYear) return n + 1;
                // Leap year calculation looks different from IsLeapYear since y1, y4,
                // and y100 are relative to year 1, not year 0
                bool leapYear = y1 == 3 && (y4 != 24 || y100 == 3);
                int[] days = leapYear ? DaysToMonth366 : DaysToMonth365;
                // All months have less than 32 days, so n >> 5 is a good conservative
                // estimate for the month
                int m = n >> 5 + 1;
                // m = 1-based month number
                while (n >= days[m]) m++;
                // If month was requested, return it
                if (part == DatePartMonth) return m;
                // Return 1-based day-of-month
                return n - days[m - 1] + 1;
            }

            [DllImport("kernel32.dll")]
            private static extern bool FileTimeToLocalFileTime(ref long lpFileTime, out long lpLocalFileTime);

            [DllImport("kernel32.dll")]
            private static extern bool GetSystemTimeAsFileTime(out long lpLocalFileTime);
        }

     

     

    what do you think about it?

     

     

    Tuesday, April 13, 2010 7:59 PM

All replies

  • If you need to examine the time so often that you care about a difference of 16 ticks, you'll probably also be unhappy with the resolution of this timer which is approximately 10 milliseconds.  This is 25,000 times longer than 4 ticks.

    > what do you think about it?

    Actually, I'd be a lot more impressed if you can give an explanation of how this code makes your real-world application perform measurably better.

     

    Wednesday, April 14, 2010 1:54 AM
  • the resolution of Stopwatch (QueryPerformanceCounter) is 0.333 nano second on my computer,

    but dateTime / GetSystemTimeAsFileTime resolution is approximatly 10ms - 15ms

    even with filetime having a resolution of 100 nanosecond

     look here:

    http://msdn.microsoft.com/en-us/library/ms724284(VS.85).aspx

    http://msdn.microsoft.com/en-us/magazine/cc163996.aspx

     

    and example on how it can help:

    i saw a lot of databases that save on the row , the update date which is done with date time now,

    but if they can use my DateTime.Now and save the dateData on the DB

    and when the application is starting again , it will instantiate all the DateTime from the dateDate

    it will be faster

     

    but for that to happen

     

    the datetime.now code inside the dotnet should be replaced with my version of it

    or that i can use .Net-Sploit to do that

    http://www.applicationsecurity.co.il/english/NETFrameworkRootkits/tabid/161/Default.aspx

     

     

    also i remembered what exactly was the problem with the ToLocalTime

    it calls inside to GetDaylightChanges which causes boxing

    for example:

    object key = year; //year is int

     if (!this.m_CachedDaylightChanges.Contains(key))

    but even if they fix it , my method of converting utc to local time is faster

     

    also it's faster than this method:

     

        [DllImport("kernel32.dll")]

        static extern void GetLocalTime(out SYSTEMTIME time);

     

        [StructLayout(LayoutKind.Sequential)]

        private struct SYSTEMTIME

        {

            public ushort Year;

            public ushort Month;

            public ushort DayOfWeek;

            public ushort Day;

            public ushort Hour;

            public ushort Minute;

            public ushort Second;

            public ushort Milliseconds;

        }

     

        public static DateTime LocalTime

        {

            get

            {

                SYSTEMTIME nativeTime;

                GetLocalTime(out nativeTime);

     

                return new DateTime(nativeTime.Year, nativeTime.Month, nativeTime.Day,

                        nativeTime.Hour, nativeTime.Minute, nativeTime.Second,

                        nativeTime.Milliseconds, DateTimeKind.Local);

            }

        }

     

     

    it's faster because inside the function GetLocalTime(out localtime)

    there is a call to

    GetSystemTimeAsFileTime(&FileTime);
    FileTimeToLocalFileTime(&FileTime, &LocalFileTime);
    FileTimeToSystemTime(&LocalFileTime, lpSystemTime);

     

    and i only call to

    GetSystemTimeAsFileTime

    FileTimeToLocalFileTime

    to get the ticks

     

    and then constructing the date time like this

    DateTime(nativeTime.Year, nativeTime.Month, nativeTime.Day,

                        nativeTime.Hour, nativeTime.Minute, nativeTime.Second,

                        nativeTime.Milliseconds, DateTimeKind.Local);

    is slower because from all of that parameters it needs to calculate the ticks

    but before it called FileTimeToSystemTime it already had the ticks and now it's recalculating it

     

    and my method construct it with assigning the dateData directly

     

    so this is the fastest and most direct way to get DateTime.Now:

     

            public static DateTime Now
            {
                get
                {
                    long systemTime;
                    GetSystemTimeAsFileTime(out systemTime);
                    long localTime;
                    FileTimeToLocalFileTime(ref systemTime, out localTime);

                    return new DateTime(((UInt64) (localTime + FileTimeOffset)) | KindUtc);
                }
            }

     

    the only way to make this faster is to calculate the difference between systemTime and localtime like this:

    diff = localTime-systemTime

    and than replace the call to FileTimeToLocalFileTime with something like this:

     

    long systemTime;
    GetSystemTimeAsFileTime(out systemTime);

    systemTime += 0x00002ded320a;

    return new DateTime(((UInt64) (systemTime + FileTimeOffset)) | KindUtc);

    but this is dangerous because of daylight saving time , and if you change timezone it will not work

     

    maybe there is faster way in assembler some how with the RDTSC instruction

    RDTSC = Read Time Stamp Counter  returns the number of clock cycles since the CPU was powered up or reset. 

    like this for example:

    KeQueryPerformanceCounter(PLARGE_INTEGER PerformanceFrequency)
    {
        LARGE_INTEGER Result;

        if(PerformanceFrequency) PerformanceFrequency->QuadPart = 100000000;
        Result.HighPart = HalpDecrementerRoll;
        Result.LowPart = rdtsc();
        return Result;
    }

    or this:

    unsigned long long int rdtsc(void)
    {
       unsigned long long int x;
       unsigned a, d;

       __asm__ volatile("rdtsc" : "=a" (a), "=d" (d));

       return ((unsigned long long)a) | (((unsigned long long)d) << 32);;
    }

    but i need to find a way to convert it to filetime and utc or localtime

     

    i found something about reading the real time clock from cmos

    static unsigned long __get_cmos_time(void)
         {
             unsigned int year, mon, day, hour, min, sec;
        
             sec  = CMOS_READ(RTC_SECONDS);
             min  = CMOS_READ(RTC_MINUTES);
             hour = CMOS_READ(RTC_HOURS);
             day  = CMOS_READ(RTC_DAY_OF_MONTH);
             mon  = CMOS_READ(RTC_MONTH);
             year = CMOS_READ(RTC_YEAR);
        
             if ( !(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD )
             {
                 BCD_TO_BIN(sec);
                 BCD_TO_BIN(min);
                 BCD_TO_BIN(hour);
                 BCD_TO_BIN(day);
                 BCD_TO_BIN(mon);
                 BCD_TO_BIN(year);
             }
        
             if ( (year += 1900) < 1970 )
                 year += 100;
        
             return mktime(year, mon, day, hour, min, sec);
      }

    http://webcache.googleusercontent.com/search?q=cache:VPiUW34g_1oJ:www.codepedia.com/1/CMOS_C+hxxp://www.codepedia.com/1/CMOS_C&cd=1&hl=iw&ct=clnk&gl=il

    Wednesday, April 14, 2010 9:56 AM
  • i found another ways to read time from RTClock:

    from singularity & cosmos:

     

    using Microsoft.Singularity.Io;
    
    using System;
    using System.Diagnostics;
    using System.Runtime.CompilerServices;
    using System.Threading;
    
    using Microsoft.Singularity.Configuration;
    
    namespace Microsoft.Singularity.Hal
    {
      [DriverCategory]
      [Signature("/pnp/PNP0B00")]
      public sealed class RtcResources : DriverCategoryDeclaration
      {
        [IoPortRange(0, Default = 0x0070, Length = 0x02)]
        public IoPortRange port1;
    
        [IoIrqRange(1, Default = 0x08)]
        public IoIrqRange irq1;
      }
    
      /// <remarks>
      /// Class <c>RTClock</c> represents the system
      /// Real-Time Clock. RTC chips in PCs are based on the
      /// Motorola MC146818A. It provides timing resolution
      /// of 1 second, but can generate periodic interrupts
      /// more frequently.
      /// </remarks>
      [ CLSCompliant(false) ]
      public sealed class RTClockApic
      {
        // Data registers
        private const byte DS1287_SECONDS    = 0x00;
        private const byte DS1287_SECONDS_ALARM = 0x01;
        private const byte DS1287_MINUTES    = 0x02;
        private const byte DS1287_MINUTES_ALARM = 0x03;
        private const byte DS1287_HOURS     = 0x04;
        private const byte DS1287_HOURS_ALARM  = 0x05;
        private const byte DS1287_DAY_OF_WEEK  = 0x06; // 1 is Sunday
        private const byte DS1287_DAY_OF_MONTH = 0x07;
        private const byte DS1287_MONTH     = 0x08;
        private const byte DS1287_YEAR     = 0x09;
        private const byte DS1287_USERDATA   = 0x32; // Randomly chosen user reg.
        // Control registers and masks
        private const byte DS1287_A       = 0x0a;
        private const byte DS1287_A_UIP     = 0x80; // Update Cycle Status
        private const byte DS1287_A_DIVON    = 0x20; // Osc and Freq Div on
        private const byte DS1287_A_8KHZ    = 0x03;
        private const byte DS1287_A_4KHZ    = 0x04;
        private const byte DS1287_A_2KHZ    = 0x05;
        private const byte DS1287_A_1KHZ    = 0x06;
        private const byte DS1287_A_64HZ    = 0x0a;
        private const byte DS1287_A_2HZ     = 0x0f;
        private const byte DS1287_B       = 0x0b;
        private const byte DS1287_B_UTI     = 0x80; // Update Transfer Inhibit
        private const byte DS1287_B_PIE     = 0x40; // Periodic Interrupt Enable
        private const byte DS1287_B_24H     = 0x20; // Alarm Interrupt Enable
        private const byte DS1287_B_UIE     = 0x10; // Update Cycle Inter. Enable
        private const byte DS1287_B_SQWE    = 0x08; // Square-Wave Enable
        private const byte DS1287_B_DF     = 0x04; // Data Format
        private const byte DS1287_B_DF_BINARY  = 0x04; //  Binary
        private const byte DS1287_B_DF_BCD   = 0x00; //  Binary Coded Decimal (BCD)
        private const byte DS1287_B_HF     = 0x02; // Hour Format
        private const byte DS1287_B_HF_24H   = 0x02; //  24-hour format
        private const byte DS1287_B_HF_12H   = 0x00; //  12-hour format
        private const byte DS1287_B_DSE     = 0x01; // Daylight Saving Enable
        private const byte DS1287_C       = 0x0c;
        private const byte DS1287_C_UF     = 0x10; // Update Event Flag
        private const byte DS1287_C_AF     = 0x20; // Alarm Event Flag
        private const byte DS1287_C_PF     = 0x40; // Periodic Event Flag
        private const byte DS1287_C_INTF    = 0x80; // Interrupt Request Flag
        private const byte DS1287_D       = 0x0d;
        private const byte DS1287_D_VRT     = 0x80; // Valid RAM and Time
    
        private PnpConfig config;
        private IoPort  rtcadd;
        private IoPort  rtcdat;
    
        private Apic apic;
        private byte irq;
        private byte interrupt;
        internal volatile uint irqCount = 0;
    
        private SpinLock rtcSpinLock; // Protects rtcBootTime and rtc update
        private long rtcBootTime;
    
        private byte firstStatus;
    
        // Constructor
        internal RTClockApic(PnpConfig config, Apic apic)
        {
    
          int cpuId;
          Microsoft.Singularity.Hal.Platform p = Microsoft.Singularity.Hal.Platform.ThePlatform;
          cpuId = p.ApicId;
    
          DebugStub.Print("RTClock: create\n");
    
          // /pnp/08/03/01/PNP0B00 0003 cfg dis : ISA RTC Controller : AT RTC
          // IRQ mask=0100 type=47
          // I/O Port inf=01 min=0070 max=0070 aln=01 len=02 0070..0071
    
          this.config   = config;
          this.irq     = ((IoIrqRange)config.DynamicRanges[1]).Irq;
          this.apic    = apic;
          this.rtcSpinLock = new SpinLock(SpinLock.Types.RTClock);
    
          rtcadd = ((IoPortRange)config.DynamicRanges[0])
            .PortAtOffset(0, 1, Access.ReadWrite);
          rtcdat = ((IoPortRange)config.DynamicRanges[0])
            .PortAtOffset(1, 1, Access.ReadWrite);
    
          if (cpuId == 0) {
            this.interrupt = Initialize();
            DebugStub.Print("RTClock: interrupt {0:x2}\n",
                    __arglist(this.interrupt));
          }
        }
    
        [NoHeapAllocation]
        private byte ReadRtc(byte addr)
        {
          IoResult result;
    
          result = rtcadd.Write8NoThrow(addr);
          DebugStub.Assert(IoResult.Success == result);
    
          byte value;
          result = rtcdat.Read8NoThrow(out value);
          DebugStub.Assert(IoResult.Success == result);
          return value;
        }
    
        [NoHeapAllocation]
        private void WriteRtc(byte addr, byte val)
        {
          IoResult result;
    
          result = rtcadd.Write8NoThrow(addr);
          DebugStub.Assert(IoResult.Success == result);
    
          result = rtcdat.Write8NoThrow(val);
          DebugStub.Assert(IoResult.Success == result);
        }
    
        private byte Initialize()
        {
          if ((ReadRtc(DS1287_D) & DS1287_D_VRT) == 0) {
            DebugStub.Print("RTClock weak or defective power source.\n");
          }
    
          rtcBootTime = PullRtcTime();
    
          DebugStub.Print("RTClock::Start()\n");
    
          // Enable and clear interrupts
          // NB it may take 500ms for first interrupt to be generated.
    
          WriteRtc(DS1287_B, DS1287_B_UTI);
          WriteRtc(DS1287_A, DS1287_A_2HZ);
          WriteRtc(DS1287_A, DS1287_A_DIVON | DS1287_A_2HZ);
          WriteRtc(DS1287_B, DS1287_B_HF_24H | DS1287_B_DF_BCD | DS1287_B_PIE | DS1287_B_SQWE);
    
          // apic.SetIrqPriority(irq, IrqPriority.High);
          apic.EnableIrq(irq);
    
          // Here we wait for the first interrupt to be
          // raised, which might be upto 0.5 seconds. This
          // wait is based on experience, ie not waiting with
          // some boxes (the infamous Ryan's TPM machine for
          // instance) leads to the clock interrupt never being
          // raised.
    
          while ((ReadRtc(DS1287_C) & DS1287_C_PF) != DS1287_C_PF) {
            // TODO: Break out after 1 second and
            // report an error.
          }
          firstStatus = DS1287_C_PF;
    
          byte ivValue = apic.IrqToInterrupt(irq);
    
          return ivValue;
        }
    
        private int Log2(uint value)
        {
          int l = 0;
          if ((value & 0xffff0000u) != 0) {
            l += 16; value >>= 16;
          }
          if ((value & 0x0000ff00u) != 0) {
            l += 8; value >>= 8;
          }
          if ((value & 0x000000f0u) != 0) {
            l += 4; value >>= 4;
          }
          if ((value & 0x0000000cu) != 0) {
            l += 2; value >>= 2;
          }
          if ((value & 0x0000000au) != 0) {
            l += 1; value >>= 1;
          }
          return l;
        }
    
        internal bool SetFrequency(uint frequency)
        {
          if (frequency > 8192 || frequency < 2) {
            return false;
          }
    
          if (Processor.SamplingEnabled()) {
            frequency = 8192;
          }
    
          int a = DS1287_A_DIVON;
          a |= (0xf - (Log2(frequency) - 1)) & 0xf;
          DebugStub.Assert((a & 0xf0) == DS1287_A_DIVON);
    
          WriteRtc(DS1287_A, (byte) a);
          WriteRtc(DS1287_B, DS1287_B_HF_24H | DS1287_B_DF_BCD | DS1287_B_PIE | DS1287_B_SQWE);
    
          return true;
        }
    
        public void ReleaseResources()
        {
          apic.DisableIrq(irq);
        }
    
        [NoHeapAllocation]
        public void ClearInterrupt()
        {
          byte status = ReadRtc(DS1287_C);
          status |= firstStatus;
          firstStatus = 0;
    
          const byte CMask = DS1287_C_INTF | DS1287_C_PF;
    
          DebugStub.Assert((status & CMask) == CMask);
    
          if ((status & DS1287_C_PF) != 0) {
            this.irqCount++;
          }
          apic.AckIrq(apic.InterruptToIrq(this.interrupt));
        }
    
        public byte Interrupt
        {
          [NoHeapAllocation]
          get { return this.interrupt; }
        }
    
        ///////////////////////////////////////////////////////////////////////
    
        [ System.Diagnostics.Conditional("SINGULARITY_MP") ]
        [NoHeapAllocation]
        private void AcquireLock()
        {
          rtcSpinLock.Acquire();
        }
    
        [ System.Diagnostics.Conditional("SINGULARITY_MP") ]
        [NoHeapAllocation]
        private void ReleaseLock()
        {
          rtcSpinLock.Release();
        }
    
        [NoHeapAllocation]
        public long GetBootTime()
        {
          bool en = Processor.DisableInterrupts();
          try {
            AcquireLock();
            long bootTime = rtcBootTime;
            ReleaseLock();
            return bootTime;
          }
          finally {
            Processor.RestoreInterrupts(en);
          }
        }
    
        public void SetRtcTime(long newRtcTime, long kernelTicks)
        {
          bool en = Processor.DisableInterrupts();
          try {
            AcquireLock();
            long currentRtcTime = rtcBootTime + kernelTicks;
            long delta = newRtcTime - currentRtcTime;
            rtcBootTime = rtcBootTime + delta;
            PushRtcTime(newRtcTime);
            ReleaseLock();
          }
          finally {
            Processor.RestoreInterrupts(en);
          }
        }
    
        [NoHeapAllocation]
        internal static byte BcdToHex(byte bcd)
        {
          return (byte) (10 * (bcd >> 4) + (bcd & 0x0f));
        }
    
        [NoHeapAllocation]
        internal static byte HexToBcd(int hex)
        {
          int h = hex / 10;
          return (byte) ((h << 4) | (hex - h * 10));
        }
    
        private long PullRtcTime()
        {
          for (uint iters = 0; iters < 1000000; iters++) {
            bool iflag = Processor.DisableInterrupts();
    
            try {
              if ((ReadRtc(DS1287_A) & DS1287_A_UIP) != 0) {
                // Update is in progress, try again
                continue;
              }
    
              // There is no update
              // pending. The specs suggest at least
              // ~244us to read values (T_BUC)...
              byte second = BcdToHex(ReadRtc(DS1287_SECONDS));
              byte minute = BcdToHex(ReadRtc(DS1287_MINUTES));
              byte hour  = BcdToHex(ReadRtc(DS1287_HOURS));
              byte day   = BcdToHex(ReadRtc(DS1287_DAY_OF_MONTH));
              byte month  = BcdToHex(ReadRtc(DS1287_MONTH));
              byte year  = BcdToHex(ReadRtc(DS1287_YEAR));
              byte century = BcdToHex(ReadRtc(DS1287_USERDATA));
    
              // ...but we don't
              // trust the specs, particularly as we may
              // be running on emulated hardware. Retry
              // if an update is pending or appears to
              // have completed whilst reading the time.
              if ((ReadRtc(DS1287_A) & DS1287_A_UIP) != 0) {
                continue;
              }
    
              DebugStub.Print("PullRtcTime: " +
                      "{0:d4}-{1:d2}-{2:d} {3:2}:{4:d2}:{5:d2}" +
                      "\n",
                      __arglist(100*century+year, month, day,
                           hour, minute, second));
    
              DateTime d = new DateTime(century * 100 + year, month, day,
                           hour, minute, second);
              return d.Ticks;
            }
            catch (ArgumentOutOfRangeException e) {
              DebugStub.Print("PullRtcTime failed: {0}\n",
                      __arglist(e));
            }
            finally {
              Processor.RestoreInterrupts(iflag);
            }
          }
          return (new DateTime(2005, 1, 1, 0, 0, 0)).Ticks;
        }
    
        private void PushRtcTime(long dtTicks)
        {
          DateTime dt = new DateTime(dtTicks);
    
          bool iflag = Processor.DisableInterrupts();
          try {
            byte saved = ReadRtc(DS1287_B);
    
            // Set UTI bit to stop transfers between RTC
            // bytes and user buffer.
            WriteRtc(DS1287_B, (byte)(saved | DS1287_B_UTI));
            // Write new values
            WriteRtc(DS1287_SECONDS,   HexToBcd(dt.Second));
            WriteRtc(DS1287_MINUTES,   HexToBcd(dt.Minute));
            WriteRtc(DS1287_HOURS,    HexToBcd(dt.Hour));
            WriteRtc(DS1287_DAY_OF_MONTH, HexToBcd(dt.Day));
            WriteRtc(DS1287_MONTH,    HexToBcd(dt.Month));
    
            int century = dt.Year / 100;
            WriteRtc(DS1287_YEAR,     HexToBcd(dt.Year - century*100));
            WriteRtc(DS1287_USERDATA,   HexToBcd(century));
            // Clear UTI bit to enable transfers again
            WriteRtc(DS1287_B, saved);
            DebugStub.Print("PushRtcTime {3:2}:{4:d2}:{5:d2} {0}/{1}-{2:d4}\n",
                    __arglist(dt.Month, dt.Day,
                         100*century + dt.Year, dt.Hour,
                         dt.Minute, dt.Second));
          }
          finally {
            Processor.RestoreInterrupts(iflag);
          }
        }
      }
    }
    
    

     

     

    also from cosmos:

    using System;
    using System.Collections.Generic;
    using System.Text;
    
    namespace Hardware {
    	public class RTC {
    		private const ushort AddressPort = 0x70;
    		private const ushort DataPort = 0x71;
    
    		private static void WaitForReady() {
    			do {
    				IOWriteByte(AddressPort, 10);
    			}
    			while ((IOReadByte(DataPort) & 0x80) != 0);
    		}
    
    		public static byte GetSeconds() {
    			WaitForReady();
    			IOWriteByte(AddressPort, 0);
    			return FromBCD(IOReadByte(DataPort));
    		}
    
    		public static byte GetMinutes() {
    			WaitForReady();
    			IOWriteByte(AddressPort, 2);
    			return FromBCD(IOReadByte(DataPort));
    		}
    
    		public static byte GetHours() {
    			WaitForReady();
    			IOWriteByte(AddressPort, 4);
          return FromBCD(IOReadByte(DataPort));
    		}
    
        public static void IOWriteByte(ushort aPort, byte aData) {
    	__asm{
       		Mov EDX,[EBP+0xC] 
       		Mov EAX,[EBP+0x8]
       		Out AL
    	   }
        }
    
        public static byte IOReadByte(ushort aPort) {
    	__asm{
    	     Mov EDX,[EBP+0x8]
        	     Mov EAX,0
        	     In AL
        	     Push EAX
    	   }
    	   return 0;
        }
    
        private static byte FromBCD(byte value)
        {
          return (byte)(((value >> 4) & 0x0F) * 10 + (value & 0x0F));
        }
    
    	}
    
    	public static string Now{get{return (int)RTC.GetHours() + ":" + RTC.GetMinutes() + ":" + RTC.GetSeconds();}}
    }
    
    
    Monday, May 24, 2010 1:21 PM
  • here is an other way to get DateTime.Now:

    private static readonly long _utcOffset = (DateTime.Now.Ticks - DateTime.UtcNow.Ticks);
    
    DateTime dt = DateTime.UtcNow.AddTicks(_utcOffset);
    it is 50x faster the datetime.now
    • Edited by igalk474 Monday, June 21, 2010 2:12 PM
    Tuesday, May 25, 2010 5:38 PM
  • also , this can help you when you need to set system time from code:

        [DllImport("kernel32.dll", EntryPoint = "SetSystemTime", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)] private extern static bool SetSystemTime([In] ref SYSTEMTIME lpSystemTime);
    
        [StructLayout(LayoutKind.Sequential)]
        private struct SYSTEMTIME {
          public ushort Year;
          public ushort Month;
          public ushort DayOfWeek;
          public ushort Day;
          public ushort Hour;
          public ushort Minute;
          public ushort Second;
          public ushort Milliseconds;
    
          public SYSTEMTIME(DateTime dt) {
            //dt = dt.ToUniversalTime(); // SetSystemTime expects the SYSTEMTIME in UTC ,
     //use only if you pass Now, it's better to send UtcNow instead of converting back Now to UTC
    
            Year     = (ushort)dt.Year;
            Month    = (ushort)dt.Month;
            DayOfWeek  = (ushort)dt.DayOfWeek;
            Day     = (ushort)dt.Day;
            Hour     = (ushort)dt.Hour;
            Minute    = (ushort)dt.Minute;
            Second    = (ushort)dt.Second;
            Milliseconds = (ushort)dt.Millisecond;
          }
        }
    
        public static void SetTime() {
          SYSTEMTIME systime = new SYSTEMTIME(DateTime.UtcNow);
          SetSystemTime(ref systime);//to call a user Access-Token should have SeSystemtimePrivilege & should be admin 
        }
    
    Tuesday, May 25, 2010 5:40 PM