// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Defines absolute time as used by the scheduler that is independent of the
// DateTime/timezone settings.
//
// Used to keep track of timeouts and deadline in thread scheduling
//
// ==--==
namespace System
{
using Microsoft.Singularity;
using System;
using System.Threading;
using System.Globalization;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
using CultureInfo = System.Globalization.CultureInfo;
#if !SINGULARITY_KERNEL
using Microsoft.Singularity.V1.Services;
#endif
// This value type represents an absolute time on the scheduler timeline,
// which is kernel time increasing monotonically and independently of
// the world time the machine thinks it is on.
// The reason to separate world time and scheduler time is that world time can
// change at any time due to users changing the time and date, or due to
// adjustments for accuracy or daylight-savings.
//
[StructLayout(LayoutKind.Auto)]
[AccessedByRuntime("referenced by c++ via Thread")]
public struct SchedulerTime : IComparable
{
// Number of 100ns ticks per time unit
public const long TicksPerMillisecond = 10000;
public const long TicksPerSecond = TicksPerMillisecond * 1000;
public const long TicksPerMinute = TicksPerSecond * 60;
public const long TicksPerHour = TicksPerMinute * 60;
public const long TicksPerDay = TicksPerHour * 24;
// Number of milliseconds per time unit
private const int MillisPerSecond = 1000;
private const int MillisPerMinute = MillisPerSecond * 60;
private const int MillisPerHour = MillisPerMinute * 60;
private const int MillisPerDay = MillisPerHour * 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 int DaysTo10000 = DaysPer400Years * 25;
private const long MinTicks = 0;
private const long MaxTicks = DaysTo10000 * TicksPerDay - 1;
private const long MaxMillis = (long)DaysTo10000 * MillisPerDay;
//|
public static readonly SchedulerTime MinValue = new SchedulerTime(MinTicks);
//|
public static readonly SchedulerTime MaxValue = new SchedulerTime(MaxTicks);
//
// NOTE yslin: Before the time zone is introduced, ticks is based on 1/1/0001 local time.
//
private long ticks;
// Constructs a SchedulerTime from a tick count. The ticks
// argument specifies the date as the number of 100-nanosecond intervals
// that have elapsed since 1/1/0001 12:00am.
//
//|
[NoHeapAllocation]
public SchedulerTime(long ticks) {
if (ticks < MinTicks) {
this.ticks = MinTicks;
}
else if (ticks > MaxTicks) {
this.ticks = MaxTicks;
}
else {
this.ticks = ticks;
}
}
// Returns the SchedulerTime resulting from adding the given
// TimeSpan to this SchedulerTime.
//
//|
[NoHeapAllocation]
public SchedulerTime Add(TimeSpan value) {
return new SchedulerTime(ticks + value._ticks);
}
// Returns the SchedulerTime resulting from adding a number of
// time units to this SchedulerTime.
private SchedulerTime Add(long value, int scale) {
long millis = value * scale;
if (millis <= -MaxMillis || millis >= MaxMillis) {
throw new ArgumentOutOfRangeException("ArgumentOutOfRange_AddValue");
}
return new SchedulerTime(ticks + millis * TicksPerMillisecond);
}
// Returns the SchedulerTime resulting from adding a number of
// days to this SchedulerTime. The result is computed by rounding the
// fractional number of days given by value to the nearest
// millisecond, and adding that interval to this SchedulerTime. The
// value argument is permitted to be negative.
//
//|
public SchedulerTime AddDays(long value) {
return Add(value, MillisPerDay);
}
// Returns the SchedulerTime resulting from adding a number of
// hours to this SchedulerTime. The result is computed by rounding the
// fractional number of hours given by value to the nearest
// millisecond, and adding that interval to this SchedulerTime. The
// value argument is permitted to be negative.
//
//|
public SchedulerTime AddHours(long value) {
return Add(value, MillisPerHour);
}
// Returns the SchedulerTime resulting from the given number of
// milliseconds to this SchedulerTime. The result is computed by rounding
// the number of milliseconds given by value to the nearest integer,
// and adding that interval to this SchedulerTime. The value
// argument is permitted to be negative.
//
//|
public SchedulerTime AddMilliseconds(long value) {
return Add(value, 1);
}
// Returns the SchedulerTime resulting from adding a number of
// minutes to this SchedulerTime. The result is computed by rounding the
// fractional number of minutes given by value to the nearest
// millisecond, and adding that interval to this SchedulerTime. The
// value argument is permitted to be negative.
//
//|
public SchedulerTime AddMinutes(long value) {
return Add(value, MillisPerMinute);
}
// Returns the SchedulerTime resulting from adding a number of
// seconds to this SchedulerTime. The result is computed by rounding the
// fractional number of seconds given by value to the nearest
// millisecond, and adding that interval to this SchedulerTime. The
// value argument is permitted to be negative.
//
//|
public SchedulerTime AddSeconds(long value) {
return Add(value, MillisPerSecond);
}
// Returns the SchedulerTime resulting from adding the given number of
// 100-nanosecond ticks to this SchedulerTime. The value argument
// is permitted to be negative.
//
//|
public SchedulerTime AddTicks(long value) {
return new SchedulerTime(ticks + value);
}
// Compares two SchedulerTime values, returning an integer that indicates
// their relationship.
//
//|
[NoHeapAllocation]
public static int Compare(SchedulerTime t1, SchedulerTime t2) {
if (t1.ticks > t2.ticks) return 1;
if (t1.ticks < t2.ticks) return -1;
return 0;
}
// Compares this SchedulerTime to a given object. This method provides an
// implementation of the IComparable interface. The object
// argument must be another SchedulerTime, or otherwise an exception
// occurs. Null is considered less than any instance.
//
// Returns a value less than zero if this object
//|
public int CompareTo(Object value) {
if (value == null) return 1;
if (!(value is SchedulerTime)) {
throw new ArgumentException("Arg_MustBeSchedulerTime");
}
long t = ((SchedulerTime)value).ticks;
if (ticks > t) return 1;
if (ticks < t) return -1;
return 0;
}
// Return the tick count corresponding to the given hour, minute, second.
// Will check the if the parameters are valid.
private static long TimeToTicks(int hour, int minute, int second)
{
//TimeSpan.TimeToTicks is a family access function which does no error checking, so
//we need to put some error checking out here.
if (hour >= 0 && hour < 24 && minute >= 0 && minute < 60 && second >= 0 && second < 60) {
return (TimeSpan.TimeToTicks(hour, minute, second));
}
throw new ArgumentOutOfRangeException("ArgumentOutOfRange_BadHourMinuteSecond");
}
// Checks if this SchedulerTime is equal to a given object. Returns
// true if the given object is a boxed SchedulerTime and its value
// is equal to the value of this SchedulerTime. Returns false
// otherwise.
//
//|
public override bool Equals(Object value) {
if (value is SchedulerTime) {
return ticks == ((SchedulerTime)value).ticks;
}
return false;
}
// Compares two SchedulerTime values for equality. Returns true if
// the two SchedulerTime values are equal, or false if they are
// not equal.
//
//|
[NoHeapAllocation]
public static bool Equals(SchedulerTime t1, SchedulerTime t2) {
return t1.ticks == t2.ticks;
}
// Returns the date part of this SchedulerTime. The resulting value
// corresponds to this SchedulerTime with the time-of-day part set to
// zero (midnight).
//
//|
public SchedulerTime Date {
get { return new SchedulerTime(ticks - ticks % TicksPerDay); }
}
// Returns the hash code for this SchedulerTime.
//
//|
public override int GetHashCode() {
return (int)ticks ^ (int)(ticks >> 32);
}
public long TotalDays {
[NoHeapAllocation]
get { return (ticks / TicksPerDay); }
}
// Returns the hour part of this SchedulerTime. The returned value is an
// integer between 0 and 23.
//
//|
public int Hour {
[NoHeapAllocation]
get { return (int)((ticks / TicksPerHour) % 24); }
}
// Returns the millisecond part of this SchedulerTime. The returned value
// is an integer between 0 and 999.
//
//|
public int Millisecond {
[NoHeapAllocation]
get { return (int)((ticks / TicksPerMillisecond) % 1000); }
}
// Returns the minute part of this SchedulerTime. The returned value is
// an integer between 0 and 59.
//
//|
public int Minute {
[NoHeapAllocation]
get { return (int)((ticks / TicksPerMinute) % 60); }
}
// Returns a SchedulerTime 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 SchedulerTime Now {
[NoHeapAllocation]
#if SINGULARITY_KERNEL
get { return new SchedulerTime(SystemClock.KernelUpTime.Ticks); }
#else
get { return new SchedulerTime(ProcessService.GetUpTime().Ticks); }
#endif
}
// Returns the second part of this SchedulerTime. The returned value is
// an integer between 0 and 59.
//
//|
public int Second {
[NoHeapAllocation]
get { return (int)((ticks / TicksPerSecond) % 60); }
}
// Returns the tick count for this SchedulerTime. The returned value is
// the number of 100-nanosecond intervals that have elapsed since 1/1/0001
// 12:00am.
//
//|
public long Ticks {
[NoHeapAllocation]
get { return ticks; }
}
// Returns the time-of-day part of this SchedulerTime. The returned value
// is a TimeSpan that indicates the time elapsed since midnight.
//
//|
public TimeSpan TimeOfDay {
get { return new TimeSpan(ticks % TicksPerDay); }
}
//|
public TimeSpan Subtract(SchedulerTime value) {
return new TimeSpan(ticks - value.ticks);
}
//|
public SchedulerTime Subtract(TimeSpan value) {
return new SchedulerTime(ticks - value._ticks);
}
//|
public override String ToString() {
return String.Format("{0:d} days {1:d}:{2:d}:{3:d}",
TotalDays, Hour, Minute, Second);
}
//|
[NoHeapAllocation]
public static SchedulerTime operator +(SchedulerTime d, TimeSpan t) {
if (t == TimeSpan.Infinite) {
return MaxValue;
}
return new SchedulerTime(d.ticks + t._ticks);
}
//|
[NoHeapAllocation]
public static SchedulerTime operator -(SchedulerTime d, TimeSpan t) {
return new SchedulerTime(d.ticks - t._ticks);
}
//|
[NoHeapAllocation]
public static TimeSpan operator -(SchedulerTime d1, SchedulerTime d2) {
return new TimeSpan(d1.ticks - d2.ticks);
}
//|
[NoHeapAllocation]
public static bool operator ==(SchedulerTime d1, SchedulerTime d2) {
return d1.ticks == d2.ticks;
}
//|
[NoHeapAllocation]
public static bool operator !=(SchedulerTime d1, SchedulerTime d2) {
return d1.ticks != d2.ticks;
}
//|
[NoHeapAllocation]
public static bool operator <(SchedulerTime t1, SchedulerTime t2) {
return t1.ticks < t2.ticks;
}
//|
[NoHeapAllocation]
public static bool operator <=(SchedulerTime t1, SchedulerTime t2) {
return t1.ticks <= t2.ticks;
}
//|
[NoHeapAllocation]
public static bool operator >(SchedulerTime t1, SchedulerTime t2) {
return t1.ticks > t2.ticks;
}
//|
[NoHeapAllocation]
public static bool operator >=(SchedulerTime t1, SchedulerTime t2) {
return t1.ticks >= t2.ticks;
}
}
}