//----------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. // //----------------------------------------------------------------------- namespace Microsoft.Isam.Esent.Interop { using System; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Runtime.InteropServices; /// /// Describes a date/time when a backup occurred. /// [SuppressMessage( "Microsoft.StyleCop.CSharp.NamingRules", "SA1305:FieldNamesMustNotUseHungarianNotation", Justification = "This should match the name of the unmanaged structure.")] [StructLayout(LayoutKind.Sequential)] [Serializable] public struct JET_BKLOGTIME : IEquatable, IJET_LOGTIME { /// /// The time in seconds. This value can be 0 to 59. /// private readonly byte bSeconds; /// /// The time in minutes. This value can be 0 to 59. /// private readonly byte bMinutes; /// /// The time in hours. This value can be 0 to 23. /// private readonly byte bHours; /// /// The day of the month. This value can be 0 to 31. 0 is /// used when the structure is null. /// private readonly byte bDays; /// /// The month. This value can be 0 to 12. 0 is /// used when the structure is null. /// private readonly byte bMonth; /// /// The year of the event, offset by 1900. /// private readonly byte bYear; /// /// IsUTC flag at the first bit. Starting from win8, milliseconds (low part) is filled at left 7 bits. /// private readonly byte bFiller1; /// /// OSSnapshot flag at the first bit, Starting from win8, milliseconds (high part) is filled at following 3 bits. Other bits are reserved. /// private readonly byte bFiller2; /// /// Initializes a new instance of the struct. /// /// /// The DateTime to initialize the structure with. /// /// /// True if this time is for a snapshot backup. /// internal JET_BKLOGTIME(DateTime time, bool isSnapshot) { this.bSeconds = checked((byte)time.Second); this.bMinutes = checked((byte)time.Minute); this.bHours = checked((byte)time.Hour); this.bDays = checked((byte)time.Day); this.bMonth = checked((byte)time.Month); this.bYear = checked((byte)(time.Year - 1900)); // bFiller1: fTimeIsUTC at the first bit, bMillisecondsLow at left 7 bits this.bFiller1 = (time.Kind == DateTimeKind.Utc) ? (byte)0x1 : (byte)0; this.bFiller1 |= checked((byte)((time.Millisecond & 0x7F) << 1)); // bFiller2: fOSSnapshot at the first bit, bMillisecondsHigh at following 3 bits this.bFiller2 = isSnapshot ? (byte)0x1 : (byte)0; this.bFiller2 |= checked((byte)((time.Millisecond & 0x380) >> 6)); } /// /// Gets a value indicating whether the JET_BKLOGTIME has a null value. /// public bool HasValue { get { return 0 != this.bMonth && 0 != this.bDays; } } /// /// Gets a value indicating whether the JET_BKLOGTIME is in UTC. /// [SuppressMessage( "Microsoft.StyleCop.CSharp.NamingRules", "SA1300:ElementMustBeginWithUpperCaseLetter", Justification = "This should match the unmanaged API, which isn't capitalized.")] public bool fTimeIsUTC { get { return 0 != (this.bFiller1 & 0x1); } } /// /// Gets a value indicating whether the JET_BKLOGTIME is for a snapshot backup. /// [SuppressMessage( "Microsoft.StyleCop.CSharp.NamingRules", "SA1300:ElementMustBeginWithUpperCaseLetter", Justification = "This should match the unmanaged API, which isn't capitalized.")] public bool fOSSnapshot { get { return 0 != (this.bFiller2 & 0x1); } } /// /// Determines whether two specified instances of JET_BKLOGTIME /// are equal. /// /// The first instance to compare. /// The second instance to compare. /// True if the two instances are equal. public static bool operator ==(JET_BKLOGTIME lhs, JET_BKLOGTIME rhs) { return lhs.Equals(rhs); } /// /// Determines whether two specified instances of JET_BKLOGTIME /// are not equal. /// /// The first instance to compare. /// The second instance to compare. /// True if the two instances are not equal. public static bool operator !=(JET_BKLOGTIME lhs, JET_BKLOGTIME rhs) { return !(lhs == rhs); } /// /// Generate a DateTime representation of this JET_BKLOGTIME. /// /// /// A DateTime representing the JET_BKLOGTIME. If the JET_BKLOGTIME /// is null then null is returned. /// public DateTime? ToDateTime() { if (!this.HasValue) { return null; } return new DateTime( this.bYear + 1900, this.bMonth, this.bDays, this.bHours, this.bMinutes, this.bSeconds, checked((int)((((uint)this.bFiller2 & 0xE) << 6) | (((uint)this.bFiller1 & 0xFE) >> 1))), this.fTimeIsUTC ? DateTimeKind.Utc : DateTimeKind.Local); } /// /// Generate a string representation of the structure. /// /// The structure as a string. public override string ToString() { return string.Format( CultureInfo.InvariantCulture, "JET_BKLOGTIME({0}:{1}:{2}:{3}:{4}:{5}:0x{6:x}:0x{7:x})", this.bSeconds, this.bMinutes, this.bHours, this.bDays, this.bMonth, this.bYear, this.bFiller1, this.bFiller2); } /// /// Returns a value indicating whether this instance is equal /// to another instance. /// /// An object to compare with this instance. /// True if the two instances are equal. public override bool Equals(object obj) { if (obj == null || this.GetType() != obj.GetType()) { return false; } return this.Equals((JET_BKLOGTIME)obj); } /// /// Returns the hash code for this instance. /// /// The hash code for this instance. public override int GetHashCode() { // None of the members are larger than a byte and many use fewer than // all 8 bits (e.g. a month count uses only 4 bits). Spread the members // out through the 32-bit hash value. // (This is better than the default implementation of GetHashCode, which // easily aliases different JET_BKLOGTIMES to the same hash code) return this.bSeconds.GetHashCode() ^ (this.bMinutes << 6) ^ (this.bHours << 12) ^ (this.bDays << 17) ^ (this.bMonth << 22) ^ (this.bYear << 24) ^ this.bFiller1 ^ (this.bFiller2 << 8); } /// /// Returns a value indicating whether this instance is equal /// to another instance. /// /// An instance to compare with this instance. /// True if the two instances are equal. public bool Equals(JET_BKLOGTIME other) { return this.bSeconds == other.bSeconds && this.bMinutes == other.bMinutes && this.bHours == other.bHours && this.bDays == other.bDays && this.bMonth == other.bMonth && this.bYear == other.bYear && this.bFiller1 == other.bFiller1 && this.bFiller2 == other.bFiller2; } } }