/* * Yubeshi GPS Parser * * This software is distributed under a zlib-style license. * See license.txt for more information. */ using System; using System.Collections.Generic; using System.Text; namespace Yubeshi { public struct GpsTime : IComparable { #region fields public static readonly DateTime Origin; private int week; private decimal timeOfWeek; private bool rounded; private static readonly DateTime[] leapTiming; private static int cumulativeLeapSecond; // 1e7 * 60 * 60 * 24 * 7 private const long ticksOfWeek = 6048000000000; #endregion #region constructors public GpsTime(decimal timeOfWeek) : this(GpsTime.WeekOfToday, timeOfWeek, true) { } public GpsTime(int week, decimal timeOfWeek) : this(week, timeOfWeek, week < 1024) { } public GpsTime(int week, decimal timeOfWeek, bool rounded) { if (week < 0) { throw new ArgumentException("'week' must be non-negative."); } this.week = rounded ? week + 1024 : week; this.timeOfWeek = timeOfWeek; this.rounded = rounded; } public GpsTime(DateTime time) { DateTime utc = time.ToUniversalTime(); long ticks = (time - Origin).Ticks; if (ticks < 0) { throw new ArgumentException( "GpsTime represents times since 00:00:00, 6 Jan. 1980."); } for (int i = 0; i < leapTiming.Length; ++i) { if (utc < leapTiming[i]) { break; } ticks += 10000000; // 1 / 100e-9 } rounded = false; week = (int)(ticks / ticksOfWeek); timeOfWeek = (ticks % ticksOfWeek) * 100e-9m; } static GpsTime() { Origin = new DateTime(1980, 1, 6, 0, 0, 0); leapTiming = new DateTime[]{ new DateTime(1981, 7, 1, 0, 0, 0, DateTimeKind.Utc), new DateTime(1982, 7, 1, 0, 0, 0, DateTimeKind.Utc), new DateTime(1983, 7, 1, 0, 0, 0, DateTimeKind.Utc), new DateTime(1985, 7, 1, 0, 0, 0, DateTimeKind.Utc), new DateTime(1988, 1, 1, 0, 0, 0, DateTimeKind.Utc), new DateTime(1990, 1, 1, 0, 0, 0, DateTimeKind.Utc), new DateTime(1991, 1, 1, 0, 0, 0, DateTimeKind.Utc), new DateTime(1992, 7, 1, 0, 0, 0, DateTimeKind.Utc), new DateTime(1993, 7, 1, 0, 0, 0, DateTimeKind.Utc), new DateTime(1994, 7, 1, 0, 0, 0, DateTimeKind.Utc), new DateTime(1996, 1, 1, 0, 0, 0, DateTimeKind.Utc), new DateTime(1997, 7, 1, 0, 0, 0, DateTimeKind.Utc), new DateTime(1999, 1, 1, 0, 0, 0, DateTimeKind.Utc), new DateTime(2006, 1, 1, 0, 0, 0, DateTimeKind.Utc), new DateTime(2009, 1, 1, 0, 0, 0, DateTimeKind.Utc) }; } #endregion #region properties public int Week { get { return week; } } public decimal TimeOfWeek { get { return timeOfWeek; } } public bool Rounded { get { return rounded; } } public static int CumulativeLeapSecond { get { return cumulativeLeapSecond; } set { cumulativeLeapSecond = value; } } public static GpsTime Now { get { return new GpsTime(DateTime.UtcNow); } } public static int WeekOfToday { get { return Now.Week; } } #endregion #region public methods public int CompareTo(object value) { GpsTime otherTime; if (value is GpsTime) { otherTime = (GpsTime)value; } else if(value is DateTime) { otherTime = new GpsTime((DateTime)value); } else { throw new ArgumentException("'value' is not a time."); } if (rounded || otherTime.rounded) { throw new ArgumentException("values must be absolute time."); } if (week == otherTime.week) { return timeOfWeek.CompareTo(otherTime.timeOfWeek); } return week.CompareTo(otherTime.week); } public DateTime ToLocalTime() { return ToUtc().ToLocalTime(); } public DateTime ToUtc() { long ticks = week * ticksOfWeek + (long)(timeOfWeek * 1e7m); ticks += Origin.Ticks; DateTime time = new DateTime(ticks, DateTimeKind.Utc); TimeSpan oneSecond = new TimeSpan(0, 0, 0, 1); for (int i = 0; i < leapTiming.Length; ++i) { if (time < leapTiming[i]) { break; } time -= oneSecond; } return time; } public int LeapSecond { get { return 0; } } #endregion } }