[StructLayout(LayoutKind.Sequential)]
private struct SYSTEMTIME {
[MarshalAs(UnmanagedType.U2)] public short Year;
[MarshalAs(UnmanagedType.U2)] public short Month;
[MarshalAs(UnmanagedType.U2)] public short DayOfWeek;
[MarshalAs(UnmanagedType.U2)] public short Day;
[MarshalAs(UnmanagedType.U2)] public short Hour;
[MarshalAs(UnmanagedType.U2)] public short Minute;
[MarshalAs(UnmanagedType.U2)] public short Second;
[MarshalAs(UnmanagedType.U2)] public short Milliseconds;
public SYSTEMTIME( DateTime dt )
{
dt = dt.ToUniversalTime(); // SetSystemTime expects the SYSTEMTIME in UTC
Year = (short)dt.Year;
Month = (short)dt.Month;
DayOfWeek = (short)dt.DayOfWeek;
Day = (short)dt.Day;
Hour = (short)dt.Hour;
Minute = (short)dt.Minute;
Second = (short)dt.Second;
Milliseconds = (short)dt.Millisecond;
}
}
<StructLayout(LayoutKind.Sequential)> _
Private Structure SYSTEMTIME
<MarshalAs(UnmanagedType.U2)> Public Year As Short
<MarshalAs(UnmanagedType.U2)> Public Month As Short
<MarshalAs(UnmanagedType.U2)> Public DayOfWeek As Short
<MarshalAs(UnmanagedType.U2)> Public Day As Short
<MarshalAs(UnmanagedType.U2)> Public Hour As Short
<MarshalAs(UnmanagedType.U2)> Public Minute As Short
<MarshalAs(UnmanagedType.U2)> Public Second As Short
<MarshalAs(UnmanagedType.U2)> Public Milliseconds As Short
End Structure
Sometimes, when trying to transform this struct into a CLR DateTime, I noticed that the year is 1 year behind. I don't know why.
Please add some!
[StructLayout(LayoutKind.Sequential, Pack=2)]
internal 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();
Year = Convert.ToUInt16(dt.Year);
Month = Convert.ToUInt16(dt.Month);
DayOfWeek = Convert.ToUInt16(dt.DayOfWeek);
Day = Convert.ToUInt16(dt.Day);
Hour = Convert.ToUInt16(dt.Hour);
Minute = Convert.ToUInt16(dt.Minute);
Second = Convert.ToUInt16(dt.Second);
Milliseconds = Convert.ToUInt16(dt.Millisecond);
}
public SystemTime(ushort year, ushort month, ushort day, ushort hour = 0, ushort minute = 0, ushort second = 0, ushort millisecond = 0)
{
Year = year;
Month = month;
Day = day;
Hour = hour;
Minute = minute;
Second = second;
Milliseconds = millisecond;
DayOfWeek = 0;
}
public static implicit operator DateTime(SystemTime st)
{
if (st.Year == 0 || st == MinValue)
return DateTime.MinValue;
if (st == MaxValue)
return DateTime.MaxValue;
return new DateTime(st.Year, st.Month, st.Day, st.Hour, st.Minute, st.Second, st.Milliseconds, DateTimeKind.Local);
}
public static bool operator ==(SystemTime s1, SystemTime s2)
{
return (s1.Year == s2.Year && s1.Month == s2.Month && s1.Day == s2.Day && s1.Hour == s2.Hour && s1.Minute == s2.Minute && s1.Second == s2.Second && s1.Milliseconds == s2.Milliseconds);
}
public static bool operator !=(SystemTime s1, SystemTime s2)
{
return !(s1 == s2);
}
public static readonly SystemTime MinValue, MaxValue;
static SystemTime()
{
MinValue = new SystemTime(1601, 1, 1);
MaxValue = new SystemTime(30827, 12, 31, 23, 59, 59, 999);
}
public override bool Equals(object obj)
{
if (obj is SystemTime)
return ((SystemTime)obj) == this;
return base.Equals(obj);
}
public override int GetHashCode()
{
return base.GetHashCode();
}
}
[Serializable ]
[StructLayout(LayoutKind.Explicit, Size = 16, CharSet = CharSet.Ansi)]
public sealed class SystemTime : object, IXmlSerializable
{
#region Fields
[FieldOffset(0)] private ushort wYear;
[FieldOffset(2)] private ushort wMonth;
[FieldOffset(4)] private ushort wDayOfWeek;
[FieldOffset(6)] private ushort wDay;
[FieldOffset(8)] private ushort wHour;
[FieldOffset(10)] private ushort wMinute;
[FieldOffset(12)] private ushort wSecond;
[FieldOffset(14)] private ushort wMilliseconds;
#endregion
#region Properties
public ushort Year
{
get => wYear;
set
{
wYear = value > 1600 && value < 30828
? value
: throw new ArgumentOutOfRangeException(nameof(Year), value, null);
int daysInMonth = GetDaysInMonth(wMonth, wYear);
if (wDay > daysInMonth) wDay = (ushort) daysInMonth;
wDayOfWeek = (ushort)GetDayOfWeek(wDay, wMonth, wYear);
}
}
public ushort Month
{
get => wMonth;
set
{
wMonth = value > 0 && value < 13
? value
: throw new ArgumentOutOfRangeException(nameof(Month), value, null);
int daysInMonth = GetDaysInMonth(wMonth, wYear);
if (wDay > daysInMonth) wDay = (ushort) daysInMonth;
wDayOfWeek = (ushort)GetDayOfWeek(wDay, wMonth, wYear);
}
}
public ushort Day
{
get => wDay;
set
{
wDay = value > 0 && value <= GetDaysInMonth(wMonth, wYear)
? value
: throw new ArgumentOutOfRangeException(nameof(Day), value, null);
wDayOfWeek = (ushort)GetDayOfWeek(wDay, wMonth, wYear);
}
}
public DayOfWeek DayOfWeek
{
get => (DayOfWeek)wDayOfWeek;
}
public ushort Hour
{
get => wHour;
set => wHour = value < 24 ? value
: throw new ArgumentOutOfRangeException(nameof(Hour), value, null);
}
public ushort Minute
{
get => wMinute;
set => wMinute = value < 60 ? value
: throw new ArgumentOutOfRangeException(nameof(Minute), value, null);
}
public ushort Second
{
get => wSecond;
set => wSecond = value < 60 ? value
: throw new ArgumentOutOfRangeException(nameof(Second), value, null);
}
public ushort Milliseconds
{
get => wMilliseconds;
set => wMilliseconds = value < 1000 ? value
: throw new ArgumentOutOfRangeException(nameof(Milliseconds), value, null);
}
#endregion
#region Constructor
public SystemTime()
{
wYear = 1601;
wMonth = 1;
wDay = 1;
wDayOfWeek = (ushort) GetDayOfWeek(wDay, wMonth, wYear);
wHour = 0;
wMinute = 0;
wSecond = 0;
wMilliseconds = 0;
}
public SystemTime(long fileTime)
{
FileTimeToSystemTimeNative(fileTime, this);
}
public SystemTime(DateTime dateTime)
{
long fileTime = dateTime.ToFileTimeUtc();
SystemTime systemTime = new SystemTime();
FileTimeToSystemTimeNative(fileTime, systemTime);
}
#endregion
#region Win32 imports
[DllImport("kernel32.dll", EntryPoint = "GetSystemTime", SetLastError = true)]
private static extern void GetSystemTimeNative([Out, MarshalAs(UnmanagedType.Struct)]
SystemTime systemTime);
[DllImport("kernel32.dll", EntryPoint = "SetLocalTime", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool SetLocalTimeNative([In, MarshalAs(UnmanagedType.Struct)]
SystemTime systemTime);
[DllImport("kernel32.dll", EntryPoint = "SetSystemTime", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool SetSystemTimeNative([In, MarshalAs(UnmanagedType.Struct)]
SystemTime systemTime);
[DllImport("kernel32.dll", EntryPoint = "GetLocalTime", SetLastError = true)]
private static extern void GetLocalTimeNative([Out, MarshalAs(UnmanagedType.Struct)]
SystemTime systemTime);
[DllImport("kernel32.dll", EntryPoint = "FileTimeToSystemTime", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool FileTimeToSystemTimeNative([In, MarshalAs(UnmanagedType.I8)] long fileTime,
[Out, MarshalAs(UnmanagedType.Struct)]
SystemTime systemTime);
[DllImport("kernel32.dll", EntryPoint = "SystemTimeToFileTime", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool SystemTimeToFileTimeNative([In, MarshalAs(UnmanagedType.Struct)]
SystemTime systemTime,
[Out, MarshalAs(UnmanagedType.I8)] out long fileTime);
[DllImport("kernel32.dll", EntryPoint = "GetTickCount", SetLastError = true)]
[return: MarshalAs(UnmanagedType.U4)]
private static extern ulong GetTickCountNative();
[DllImport("kernel32.dll", EntryPoint = "GetTickCount64", SetLastError = true)]
[return: MarshalAs(UnmanagedType.U8)]
private static extern ulong GetTickCount64Native();
[DllImport("kernel32.dll", EntryPoint = "GetSystemTimeAdjustment", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool GetSystemTimeAdjustmentNative(
[Out, MarshalAs(UnmanagedType.U4)] out ulong lpTimeAdjustment,
[Out, MarshalAs(UnmanagedType.U4)] out ulong lpTimeIncrement,
[Out, MarshalAs(UnmanagedType.Bool)] out bool lpTimeAdjustmentDisabled);
[DllImport("kernel32.dll", EntryPoint = "SetSystemTimeAdjustment", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool SetSystemTimeAdjustmentNative(
[In, MarshalAs(UnmanagedType.U4)] ulong dwTimeAdjustment,
[In, MarshalAs(UnmanagedType.Bool)] bool bTimeAdjustmentDisabled);
#endregion
#region Methods
private static bool CheckIsLeapYear(int year)
{
return year % 4 == 0 && year % 100 != 0 || year % 400 == 0;
}
private int GetDaysInMonth(int month, int year)
{
return month == 2 && (year % 4 == 0 && year % 100 != 0 || year % 400 == 0) ? 29 : 28 + ((62648012 >> (month * 2)) & 3);
}
private static int GetDayOfWeek(int day, int month, int year)
{
int a = (14 - month) / 12;
int y = year - a;
int m = month + 12 * a - 2;
return ((7000 + (day + y + y / 4 - y / 100 + y / 400 + (31 * m) / 12)) % 7);
}
public long ToFileTime()
{
return SystemTimeToFileTimeNative(this, out long fileTime) ? fileTime : 0L;
}
public DateTime ToDateTime()
{
return SystemTimeToFileTimeNative(this, out long fileTime)
? DateTime.FromFileTimeUtc(fileTime)
: DateTime.MinValue;
}
public double ToUnixTime()
{
SystemTimeToFileTimeNative(this, out long fileTime);
long seconds = fileTime / 10000000;
double unixTime = seconds - 11644473600;
return Math.Round(unixTime, 2);
}
public static SystemTime FromFileTime(long fileTime)
{
SystemTime systemTime = new SystemTime();
FileTimeToSystemTimeNative(fileTime, systemTime);
return systemTime;
}
public static SystemTime FromDateTime(DateTime dateTime)
{
long fileTime = dateTime.ToFileTimeUtc();
SystemTime systemTime = new SystemTime();
FileTimeToSystemTimeNative(fileTime, systemTime);
return systemTime;
}
public static SystemTime FromUnixTime(double unixTime)
{
SystemTime systemTime = new SystemTime();
long seconds = Convert.ToInt64(Math.Floor(unixTime + 11644473600));
long fileTime = seconds * 10000000;
FileTimeToSystemTimeNative(fileTime, systemTime);
return systemTime;
}
public static bool SetLocalTime(SystemTime systemTime)
{
return systemTime != null && SetLocalTimeNative(systemTime);
}
public static bool SetLocalTime(DateTime dateTime)
{
var systemTime = FromDateTime(dateTime);
return systemTime != null && SetLocalTimeNative(systemTime);
}
public static bool SetSystemTime(SystemTime systemTime)
{
return systemTime != null && SetSystemTimeNative(systemTime);
}
public static bool SetSystemTime(DateTime dateTime)
{
var systemTime = FromDateTime(dateTime);
return systemTime != null && SetSystemTimeNative(systemTime);
}
public static SystemTime GetSystemTime()
{
SystemTime systemTime = new SystemTime();
GetSystemTimeNative(systemTime);
return systemTime;
}
public static SystemTime GetLocalTime()
{
SystemTime systemTime = new SystemTime();
GetLocalTimeNative(systemTime);
return systemTime;
}
public XmlSchema GetSchema()
{
return null;
}
public void ReadXml(XmlReader reader)
{
long fileTime = reader.ReadContentAsLong();
FileTimeToSystemTimeNative(fileTime, this);
}
public void WriteXml(XmlWriter writer)
{
SystemTimeToFileTimeNative(this, out long fileTime);
writer.WriteValue(fileTime);
}
public override bool Equals(object obj)
{
return ReferenceEquals(this, obj)
|| obj is SystemTime systemTime && this == systemTime
|| obj is long fileTime && ToFileTime() == fileTime
|| obj is DateTime dt && ToDateTime() == dt;
}
public override int GetHashCode()
{
return ToFileTime().GetHashCode();
}
public override string ToString()
{
return ToDateTime().ToString(CultureInfo.CurrentCulture);
}
public string ToString(IFormatProvider provider)
{
return ToDateTime().ToString(provider);
}
public string ToString(string format)
{
return ToDateTime().ToString(format);
}
public string ToString(string format, IFormatProvider provider)
{
return ToDateTime().ToString(format, provider);
}
#endregion
#region Operators
public static explicit operator DateTime(SystemTime systemTime)
{
return systemTime.ToDateTime();
}
public static explicit operator SystemTime(DateTime dateTime)
{
return FromDateTime(dateTime);
}
public static explicit operator long(SystemTime systemTime)
{
return systemTime.ToFileTime();
}
public static explicit operator SystemTime(long fileTime)
{
return FromFileTime(fileTime);
}
public static explicit operator double(SystemTime systemTime)
{
return systemTime.ToUnixTime();
}
public static explicit operator SystemTime(double unixTime)
{
return FromUnixTime(unixTime);
}
public static SystemTime operator +(SystemTime origin, long interval)
{
return FromFileTime(origin.ToFileTime() + interval);
}
public static SystemTime operator +(SystemTime origin, TimeSpan interval)
{
return FromDateTime(origin.ToDateTime() + interval);
}
public static long operator -(SystemTime left, SystemTime right)
{
return left.ToFileTime() - right.ToFileTime();
}
public static SystemTime operator -(SystemTime origin, long interval)
{
return FromFileTime(origin.ToFileTime() - interval);
}
public static SystemTime operator -(SystemTime origin, TimeSpan interval)
{
return FromDateTime(origin.ToDateTime() - interval);
}
public static bool operator >(SystemTime left, SystemTime right)
{
return left.ToFileTime() > right.ToFileTime();
}
public static bool operator <(SystemTime left, SystemTime right)
{
return left.ToFileTime() < right.ToFileTime();
}
public static bool operator >=(SystemTime left, SystemTime right)
{
return left.ToFileTime() >= right.ToFileTime();
}
public static bool operator <=(SystemTime left, SystemTime right)
{
return left.ToFileTime() <= right.ToFileTime();
}
public static bool operator ==(SystemTime left, SystemTime right)
{
return left == null && right == null || left?.ToFileTime() == right?.ToFileTime();
}
public static bool operator !=(SystemTime left, SystemTime right)
{
return left == null ^ right == null || left?.ToFileTime() != right?.ToFileTime();
}
#endregion
}