/// <summary> /// Constructs a <c>FudgeTime</c> from the time components of a .net <see cref="DateTime"/>, specifying the precision. /// </summary> /// <param name="dateTime"><see cref="DateTime"/> to use.</param> /// <param name="precision"><see cref="FudgeDateTimePrecision"/> for this <c>FudgeTime</c>.</param> public FudgeTime(DateTime dateTime, FudgeDateTimePrecision precision) { if (precision < FudgeDateTimePrecision.Hour) { throw new ArgumentOutOfRangeException("precision"); } TimeSpan time = dateTime.TimeOfDay; this.precision = precision; this.seconds = (int)(time.Ticks / TicksPerSecond); this.nanos = (int)(time.Ticks % TicksPerSecond) * NanosPerTick; switch (dateTime.Kind) { case DateTimeKind.Utc: this.timeZoneOffset = 0; break; case DateTimeKind.Unspecified: this.timeZoneOffset = null; break; case DateTimeKind.Local: var tzOffset = TimeZoneInfo.Local.GetUtcOffset(dateTime); this.timeZoneOffset = tzOffset.Hours * 60 + tzOffset.Minutes; break; } }
/// <summary> /// Constructs a new <c>FudgeTime</c> based on a total number of seconds and nanoseconds, with a timezone. /// </summary> /// <param name="precision"></param> /// <param name="totalSeconds"></param> /// <param name="nanoseconds"></param> /// <param name="timeZoneOffset">Timezone offset from UTC, in minutes, must be multiple of 15</param> public FudgeTime(FudgeDateTimePrecision precision, int totalSeconds, int nanoseconds, int?timeZoneOffset) { if (totalSeconds < 0 || totalSeconds >= 24 * 60 * 60) { throw new ArgumentOutOfRangeException("totalseconds"); } if (nanoseconds < 0 || nanoseconds > 999999999) { throw new ArgumentOutOfRangeException("nanoseconds"); } if (timeZoneOffset.HasValue) { if (timeZoneOffset % 15 != 0) { throw new ArgumentOutOfRangeException("timeZoneOffset", "offset must be a multiple of 15 (minutes)"); } if (timeZoneOffset < -127 * 15 || timeZoneOffset > 127 * 15) { throw new ArgumentOutOfRangeException("timeZoneOffset"); } } if (precision < FudgeDateTimePrecision.Hour) { throw new ArgumentOutOfRangeException("precision"); } this.precision = precision; this.seconds = totalSeconds; this.nanos = nanoseconds; this.timeZoneOffset = timeZoneOffset; }
internal static void WriteEncodedTime(BinaryWriter output, FudgeDateTimePrecision precision, int?timezone, int seconds, int nanos) { int firstFourBytes = (timezone.HasValue ? timezone.Value / 15 : -128) << 24; firstFourBytes |= ((int)precision) << 20; firstFourBytes |= seconds; output.Write(firstFourBytes); output.Write(nanos); }
/// <summary> /// Constructs a new <c>FudgeDateTime</c> based on a .net <see cref="DateTime"/>, specifying the precision. /// </summary> /// <param name="dateTime"></param> /// <param name="precision"></param> public FudgeDateTime(DateTime dateTime, FudgeDateTimePrecision precision) { this.date = new FudgeDate(dateTime); if (precision > FudgeDateTimePrecision.Day) { this.time = new FudgeTime(dateTime, precision); } else { this.time = FudgeTime.Midnight; } this.precision = precision; }
/// <summary> /// Constructs a new <c>FudgeDateTime</c> using a <see cref="FudgeDate"/> and <see cref="FudgeTime"/>, specifying the precision. /// </summary> /// <param name="date">Date part of the datetime.</param> /// <param name="time">Time part of the datetime, may be <c>null</c>.</param> /// <param name="precision">Precision to use.</param> public FudgeDateTime(FudgeDate date, FudgeTime time, FudgeDateTimePrecision precision) { this.date = date; if (time == null) { this.time = FudgeTime.Midnight; } else { this.time = time; } this.precision = precision; }
/// <summary> /// Constructs a <c>FudgeDateTime</c> from component values with timezone information. /// </summary> /// <param name="year"></param> /// <param name="month"></param> /// <param name="day"></param> /// <param name="hour"></param> /// <param name="minute"></param> /// <param name="second"></param> /// <param name="nanosecond"></param> /// <param name="timeZoneOffset">Timezone offset from UTC, in minutes, must be multiple of 15</param> /// <param name="precision"></param> public FudgeDateTime(int year, int month, int day, int hour, int minute, int second, int nanosecond, int timeZoneOffset, FudgeDateTimePrecision precision) { this.date = new FudgeDate(year, month, day); if (precision > FudgeDateTimePrecision.Day) { this.time = new FudgeTime(hour, minute, second, nanosecond, timeZoneOffset, precision); } else { this.time = FudgeTime.Midnight; } this.precision = precision; }
/// <summary> /// Constructs a new <c>FudgeDateTime</c> based on a .net <see cref="DateTimeOffset"/>, specifying the precision. /// </summary> /// <param name="dateTimeOffset"><see cref="DateTimeOffset"/> to use.</param> /// <param name="precision"></param> /// <remarks>The offset must be on a 15-minute boundary and within the +/- 30 hour range allowed by <c>FudgeDateTime</c>.</remarks> public FudgeDateTime(DateTimeOffset dateTimeOffset, FudgeDateTimePrecision precision) { this.date = new FudgeDate(dateTimeOffset.Date); if (precision > FudgeDateTimePrecision.Day) { int seconds = (int)(dateTimeOffset.TimeOfDay.Ticks / FudgeTime.TicksPerSecond); int nanos = (int)(dateTimeOffset.TimeOfDay.Ticks % FudgeTime.TicksPerSecond); int offset = (int)(dateTimeOffset.Offset.Ticks / FudgeTime.TicksPerSecond / 60); this.time = new FudgeTime(precision, seconds, nanos, offset); } else { // Time and offset are irrelevant this.time = FudgeTime.Midnight; } this.precision = precision; }
/// <summary> /// Converts the date to a string based on a given <see cref="FudgeDateTimePrecision"/>. /// </summary> /// <param name="precision">Precision to use.</param> /// <returns>Date as a string.</returns> public string ToString(FudgeDateTimePrecision precision) { switch (precision) { case FudgeDateTimePrecision.Millennium: return(string.Format("{0:d2}000", Year / 1000)); case FudgeDateTimePrecision.Century: return(string.Format("{0:d2}00", Year / 100)); case FudgeDateTimePrecision.Year: return(string.Format("{0:d4}", Year)); case FudgeDateTimePrecision.Month: return(string.Format("{0:d4}-{1:d2}", Year, Month)); default: return(ToString()); } }
internal static void ReadEncodedTime(BinaryReader input, out FudgeDateTimePrecision precision, out int?timeZone, out int seconds, out int nanos) { int firstFourBytes = input.ReadInt32(); nanos = input.ReadInt32(); timeZone = firstFourBytes >> 24; precision = (FudgeDateTimePrecision)((firstFourBytes >> 20) & 0x0f); seconds = firstFourBytes & 0x000fffff; if (timeZone == -128) { // No timezone timeZone = null; } else { // Timezone timeZone = timeZone.Value * 15; } }
/// <summary> /// Constructs a new <c>FudgeTime</c> based on separate hours, minutes, seconds and nanoseconds, with a timezone. /// </summary> /// <param name="hour"></param> /// <param name="minute"></param> /// <param name="second"></param> /// <param name="nanoseconds"></param> /// <param name="timeZoneOffset">Timezone offset from UTC, in minutes, must be multiple of 15</param> /// <param name="precision"></param> public FudgeTime(int hour, int minute, int second, int nanoseconds, int?timeZoneOffset, FudgeDateTimePrecision precision) { if (hour < 0 || hour > 23) { throw new ArgumentOutOfRangeException("hour"); } if (minute < 0 || minute > 59) { throw new ArgumentOutOfRangeException("minute"); } if (second < 0 || second > 59) { throw new ArgumentOutOfRangeException("second"); } if (nanoseconds < 0 || nanoseconds > 999999999) { throw new ArgumentOutOfRangeException("nanoseconds"); } if (timeZoneOffset.HasValue) { if (timeZoneOffset % 15 != 0) { throw new ArgumentOutOfRangeException("timeZoneOffset", "offset must be a multiple of 15 (minutes)"); } if (timeZoneOffset < -127 * 15 || timeZoneOffset > 127 * 15) { throw new ArgumentOutOfRangeException("timeZoneOffset"); } } if (precision < FudgeDateTimePrecision.Hour) { throw new ArgumentOutOfRangeException("precision"); } this.seconds = hour * 3600 + minute * 60 + second; this.nanos = nanoseconds; this.timeZoneOffset = timeZoneOffset; this.precision = precision; }
/// <summary> /// Constructs a new <c>FudgeTime</c> based on a total number of seconds and nanoseconds, without a timezone. /// </summary> /// <param name="precision"></param> /// <param name="totalSeconds"></param> /// <param name="nanoseconds"></param> public FudgeTime(FudgeDateTimePrecision precision, int totalSeconds, int nanoseconds) : this(precision, totalSeconds, nanoseconds, null) { }
/// <summary> /// Constructs a new <c>FudgeTime</c> based on separate hours, minutes, seconds and nanoseconds, with a timezone. /// </summary> /// <param name="hour"></param> /// <param name="minute"></param> /// <param name="second"></param> /// <param name="nanoseconds"></param> /// <param name="timeZoneOffset">Timezone offset from UTC, in minutes, must be multiple of 15</param> /// <param name="precision"></param> public FudgeTime(int hour, int minute, int second, int nanoseconds, int? timeZoneOffset, FudgeDateTimePrecision precision) { if (hour < 0 || hour > 23) throw new ArgumentOutOfRangeException("hour"); if (minute < 0 || minute > 59) throw new ArgumentOutOfRangeException("minute"); if (second < 0 || second > 59) throw new ArgumentOutOfRangeException("second"); if (nanoseconds < 0 || nanoseconds > 999999999) throw new ArgumentOutOfRangeException("nanoseconds"); if (timeZoneOffset.HasValue) { if (timeZoneOffset % 15 != 0) throw new ArgumentOutOfRangeException("timeZoneOffset", "offset must be a multiple of 15 (minutes)"); if (timeZoneOffset < -127 * 15 || timeZoneOffset > 127 * 15) throw new ArgumentOutOfRangeException("timeZoneOffset"); } if (precision < FudgeDateTimePrecision.Hour) throw new ArgumentOutOfRangeException("precision"); this.seconds = hour * 3600 + minute * 60 + second; this.nanos = nanoseconds; this.timeZoneOffset = timeZoneOffset; this.precision = precision; }
/// <summary> /// Constructs a new <c>FudgeTime</c> based on separate hours, minutes, seconds and nanoseconds, without a timezone. /// </summary> /// <param name="hour"></param> /// <param name="minute"></param> /// <param name="second"></param> /// <param name="nanoseconds"></param> /// <param name="precision"></param> public FudgeTime(int hour, int minute, int second, int nanoseconds, FudgeDateTimePrecision precision) : this(hour, minute, second, nanoseconds, null, precision) { }
/// <summary> /// Converts a string in ISO8601/RFC3339 format to a FudgeTime /// </summary> /// <param name="s">String to parse</param> /// <returns><see cref="FudgeTime"/> that the string represents.</returns> public static FudgeTime Parse(string s) { FudgeDateTimePrecision precision = FudgeDateTimePrecision.Hour; Match match = parseRegex.Match(s); if (!match.Success) throw new FormatException("String \"" + s + "\" is not a valid time format"); int hour = 0, minute = 0, second = 0, nanos = 0; int? tzOffset = null; hour = int.Parse(match.Groups[1].Value); if (match.Groups[2].Success) { minute = int.Parse(match.Groups[2].Value.Substring(1)); precision = FudgeDateTimePrecision.Minute; if (match.Groups[3].Success) { second = int.Parse(match.Groups[3].Value.Substring(1)); precision = FudgeDateTimePrecision.Second; if (match.Groups[4].Success) { string nanoStr = match.Groups[4].Value.Substring(1); int originalLen = nanoStr.Length; if (originalLen > 9) nanoStr = nanoStr.Substring(0, 9); else nanoStr = nanoStr.PadRight(9, '0'); nanos = int.Parse(nanoStr); if (originalLen >= 9) precision = FudgeDateTimePrecision.Nanosecond; else if (originalLen >= 6) precision = FudgeDateTimePrecision.Microsecond; else if (originalLen >= 3) precision = FudgeDateTimePrecision.Millisecond; } } if (match.Groups[5].Success) { // Got a time-zone string tzStr = match.Groups[5].Value; int colonPos = tzStr.IndexOf(":"); int tzHour = int.Parse(tzStr.Substring(0, colonPos)); int tzMin = int.Parse(tzStr.Substring(colonPos + 1)); if (tzHour < 0) tzMin = -tzMin; tzOffset = tzHour * 60 + tzMin; } } return new FudgeTime(hour, minute, second, nanos, tzOffset, precision); }
/// <summary> /// Constructs a new <c>FudgeTime</c> based on a total number of seconds and nanoseconds, with a timezone. /// </summary> /// <param name="precision"></param> /// <param name="totalSeconds"></param> /// <param name="nanoseconds"></param> /// <param name="timeZoneOffset">Timezone offset from UTC, in minutes, must be multiple of 15</param> public FudgeTime(FudgeDateTimePrecision precision, int totalSeconds, int nanoseconds, int? timeZoneOffset) { if (totalSeconds < 0 || totalSeconds >= 24 * 60 * 60) throw new ArgumentOutOfRangeException("totalseconds"); if (nanoseconds < 0 || nanoseconds > 999999999) throw new ArgumentOutOfRangeException("nanoseconds"); if (timeZoneOffset.HasValue) { if (timeZoneOffset % 15 != 0) throw new ArgumentOutOfRangeException("timeZoneOffset", "offset must be a multiple of 15 (minutes)"); if (timeZoneOffset < -127 * 15 || timeZoneOffset > 127 * 15) throw new ArgumentOutOfRangeException("timeZoneOffset"); } if (precision < FudgeDateTimePrecision.Hour) throw new ArgumentOutOfRangeException("precision"); this.precision = precision; this.seconds = totalSeconds; this.nanos = nanoseconds; this.timeZoneOffset = timeZoneOffset; }
/// <summary> /// Constructs a <c>FudgeTime</c> from the time components of a .net <see cref="DateTime"/>, specifying the precision. /// </summary> /// <param name="dateTime"><see cref="DateTime"/> to use.</param> /// <param name="precision"><see cref="FudgeDateTimePrecision"/> for this <c>FudgeTime</c>.</param> public FudgeTime(DateTime dateTime, FudgeDateTimePrecision precision) { if (precision < FudgeDateTimePrecision.Hour) throw new ArgumentOutOfRangeException("precision"); TimeSpan time = dateTime.TimeOfDay; this.precision = precision; this.seconds = (int)(time.Ticks / TicksPerSecond); this.nanos = (int)(time.Ticks % TicksPerSecond) * NanosPerTick; switch (dateTime.Kind) { case DateTimeKind.Utc: this.timeZoneOffset = 0; break; case DateTimeKind.Unspecified: this.timeZoneOffset = null; break; case DateTimeKind.Local: var tzOffset = TimeZoneInfo.Local.GetUtcOffset(dateTime); this.timeZoneOffset = tzOffset.Hours * 60 + tzOffset.Minutes; break; } }