Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[API Implementation]: Add Microseconds and Nanoseconds to TimeStamp, DateTime, DateTimeOffset, and TimeOnly #67666

Merged
merged 15 commits into from
Apr 14, 2022
561 changes: 538 additions & 23 deletions src/libraries/System.Private.CoreLib/src/System/DateTime.cs

Large diffs are not rendered by default.

206 changes: 206 additions & 0 deletions src/libraries/System.Private.CoreLib/src/System/DateTimeOffset.cs
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,165 @@ public DateTimeOffset(int year, int month, int day, int hour, int minute, int se
}
}

/// <summary>
/// Initializes a new instance of the <see cref="DateTimeOffset"/> structure using the
/// specified <paramref name="year"/>, <paramref name="month"/>, <paramref name="day"/>, <paramref name="hour"/>, <paramref name="minute"/>,
/// <paramref name="second"/>, <paramref name="millisecond"/>, <paramref name="microsecond"/> and <paramref name="offset"/>.
/// </summary>
/// <param name="year">The year (1 through 9999).</param>
/// <param name="month">The month (1 through 12).</param>
/// <param name="day">The day (1 through the number of days in <paramref name="month"/>).</param>
/// <param name="hour">The hours (0 through 23).</param>
/// <param name="minute">The minutes (0 through 59).</param>
/// <param name="second">The seconds (0 through 59).</param>
/// <param name="millisecond">The milliseconds (0 through 999).</param>
/// <param name="microsecond">The microseconds (0 through 999).</param>
/// <param name="offset">The time's offset from Coordinated Universal Time (UTC).</param>
/// <exception cref="ArgumentException">
/// <paramref name="offset"/> does not represent whole minutes.
/// </exception>
/// <remarks>
/// This constructor interprets <paramref name="year"/>, <paramref name="month"/> and <paramref name="day"/> as a year, month and day
/// in the Gregorian calendar. To instantiate a <see cref="DateTimeOffset"/> value by using the year, month and day in another calendar, call
/// the <see cref="DateTimeOffset(int, int, int, int, int, int, int, int, Calendar, TimeSpan)"/> constructor.
/// </remarks>
/// <exception cref="ArgumentOutOfRangeException">
/// <paramref name="year"/> is less than 1 or greater than 9999.
///
/// -or-
///
/// <paramref name="month"/> is less than 1 or greater than 12.
///
/// -or-
///
/// <paramref name="day"/> is less than 1 or greater than the number of days in <paramref name="month"/>.
///
/// -or-
///
/// <paramref name="hour"/> is less than 0 or greater than 23.
///
/// -or-
///
/// <paramref name="minute"/> is less than 0 or greater than 59.
///
/// -or-
///
/// <paramref name="second"/> is less than 0 or greater than 59.
///
/// -or-
///
/// <paramref name="millisecond"/> is less than 0 or greater than 999.
/// -or-
///
/// <paramref name="microsecond"/> is less than 0 or greater than 900.
/// </exception>
public DateTimeOffset(int year, int month, int day, int hour, int minute, int second, int millisecond, int microsecond, TimeSpan offset)
tarekgh marked this conversation as resolved.
Show resolved Hide resolved
{
_offsetMinutes = ValidateOffset(offset);

int originalSecond = second;
if (second == 60 && DateTime.s_systemSupportsLeapSeconds)
{
// Reset the leap second to 59 for now and then we'll validate it after getting the final UTC time.
second = 59;
}

_dateTime = ValidateDate(new DateTime(year, month, day, hour, minute, second, millisecond, microsecond), offset);

if (originalSecond == 60 &&
!DateTime.IsValidTimeWithLeapSeconds(_dateTime.Year, _dateTime.Month, _dateTime.Day, _dateTime.Hour, _dateTime.Minute, DateTimeKind.Utc))
{
throw new ArgumentOutOfRangeException(null, SR.ArgumentOutOfRange_BadHourMinuteSecond);
}
}

/// <summary>
/// Initializes a new instance of the <see cref="DateTimeOffset"/> structure using the
/// specified <paramref name="year"/>, <paramref name="month"/>, <paramref name="day"/>, <paramref name="hour"/>, <paramref name="minute"/>,
/// <paramref name="second"/>, <paramref name="millisecond"/>, <paramref name="microsecond"/> and <paramref name="offset"/>.
/// </summary>
/// <param name="year">The year (1 through 9999).</param>
/// <param name="month">The month (1 through 12).</param>
/// <param name="day">The day (1 through the number of days in <paramref name="month"/>).</param>
/// <param name="hour">The hours (0 through 23).</param>
/// <param name="minute">The minutes (0 through 59).</param>
/// <param name="second">The seconds (0 through 59).</param>
/// <param name="millisecond">The milliseconds (0 through 999).</param>
/// <param name="microsecond">The microseconds (0 through 999).</param>
/// <param name="calendar">The calendar that is used to interpret <paramref name="year"/>, <paramref name="month"/>, and <paramref name="day"/>.</param>
/// <param name="offset">The time's offset from Coordinated Universal Time (UTC).</param>
/// <remarks>
/// This constructor interprets <paramref name="year"/>, <paramref name="month"/> and <paramref name="day"/> as a year, month and day
/// in the Gregorian calendar. To instantiate a <see cref="DateTimeOffset"/> value by using the year, month and day in another calendar, call
/// the <see cref="DateTimeOffset(int, int, int, int, int, int, int, int, Calendar, TimeSpan)"/> constructor.
/// </remarks>
/// <exception cref="ArgumentException">
/// <paramref name="offset"/> does not represent whole minutes.
/// </exception>
/// <exception cref="ArgumentOutOfRangeException">
/// <paramref name="year"/> is not in the range supported by <paramref name="calendar"/>.
///
/// -or-
///
/// <paramref name="month"/> is less than 1 or greater than the number of months in <paramref name="calendar"/>.
///
/// -or-
///
/// <paramref name="day"/> is less than 1 or greater than the number of days in <paramref name="month"/>.
///
/// -or-
///
/// <paramref name="hour"/> is less than 0 or greater than 23.
///
/// -or-
///
/// <paramref name="minute"/> is less than 0 or greater than 59.
///
/// -or-
///
/// <paramref name="second"/> is less than 0 or greater than 59.
///
/// -or-
///
/// <paramref name="millisecond"/> is less than 0 or greater than 999.
///
/// -or-
///
/// <paramref name="microsecond"/> is less than 0 or greater than 900.
///
/// -or-
///
/// <paramref name="offset"/> is less than -14 hours or greater than 14 hours.
///
/// -or-
///
/// The <paramref name="year"/>, <paramref name="month"/>, and <paramref name="day"/> parameters
/// cannot be represented as a date and time value.
///
/// -or-
///
/// The <see cref="UtcDateTime"/> property is earlier than <see cref="MinValue"/> or later than <see cref="MaxValue"/>.
/// </exception>
public DateTimeOffset(int year, int month, int day, int hour, int minute, int second, int millisecond, int microsecond, Calendar calendar, TimeSpan offset)
deeprobin marked this conversation as resolved.
Show resolved Hide resolved
{
_offsetMinutes = ValidateOffset(offset);

int originalSecond = second;
if (second == 60 && DateTime.s_systemSupportsLeapSeconds)
{
// Reset the leap second to 59 for now and then we'll validate it after getting the final UTC time.
second = 59;
}

_dateTime = ValidateDate(new DateTime(year, month, day, hour, minute, second, millisecond, microsecond, calendar), offset);

if (originalSecond == 60 &&
!DateTime.IsValidTimeWithLeapSeconds(_dateTime.Year, _dateTime.Month, _dateTime.Day, _dateTime.Hour, _dateTime.Minute, DateTimeKind.Utc))
{
throw new ArgumentOutOfRangeException(null, SR.ArgumentOutOfRange_BadHourMinuteSecond);
}
}

// Returns a DateTimeOffset representing the current date and time. The
// resolution of the returned value depends on the system timer.
public static DateTimeOffset Now => ToLocalTime(DateTime.UtcNow, true);
Expand Down Expand Up @@ -256,6 +415,26 @@ public DateTimeOffset ToOffset(TimeSpan offset) =>
//
public int Millisecond => ClockDateTime.Millisecond;

/// <summary>
/// Gets the microsecond component of the time represented by the current <see cref="DateTimeOffset"/> object.
/// </summary>
/// <remarks>
/// If you rely on properties such as <see cref="Now"/> or <see cref="UtcNow"/> to accurately track the number of elapsed microseconds,
/// the precision of the time's microseconds component depends on the resolution of the system clock.
/// On Windows NT 3.5 and later, and Windows Vista operating systems, the clock's resolution is approximately 10000-15000 microseconds.
/// </remarks>
public int Microsecond => ClockDateTime.Microsecond;

/// <summary>
/// Gets the nanosecond component of the time represented by the current <see cref="DateTimeOffset"/> object.
/// </summary>
/// <remarks>
/// If you rely on properties such as <see cref="Now"/> or <see cref="UtcNow"/> to accurately track the number of elapsed nanosecond,
/// the precision of the time's nanosecond component depends on the resolution of the system clock.
/// On Windows NT 3.5 and later, and Windows Vista operating systems, the clock's resolution is approximately 10000000-15000000 nanoseconds.
/// </remarks>
public int Nanosecond => ClockDateTime.Nanosecond;

// Returns the minute part of this DateTimeOffset. The returned value is
// an integer between 0 and 59.
//
Expand Down Expand Up @@ -324,6 +503,33 @@ public DateTimeOffset AddHours(double hours) =>
public DateTimeOffset AddMilliseconds(double milliseconds) =>
new DateTimeOffset(ClockDateTime.AddMilliseconds(milliseconds), Offset);

/// <summary>
/// Returns a new <see cref="DateTimeOffset"/> object that adds a specified number of microseconds to the value of this instance.
/// </summary>
/// <param name="microseconds">A number of whole and fractional microseconds. The number can be negative or positive.</param>
/// <returns>
/// An object whose value is the sum of the date and time represented by the current <see cref="DateTimeOffset"/> object and the number
/// of whole microseconds represented by <paramref name="microseconds"/>.
/// </returns>
/// <remarks>
/// The fractional part of value is the fractional part of a microsecond.
/// For example, 4.5 is equivalent to 4 microseconds and 50 ticks, where one microseconds = 10 ticks.
/// However, <paramref name="microseconds"/> is rounded to the nearest microsecond; all values of .5 or greater are rounded up.
///
/// Because a <see cref="DateTimeOffset"/> object does not represent the date and time in a specific time zone,
/// the <see cref="AddMicroseconds"/> method does not consider a particular time zone's adjustment rules
/// when it performs date and time arithmetic.
/// </remarks>
/// <exception cref="ArgumentOutOfRangeException">
/// The resulting <see cref="DateTimeOffset"/> value is less than <see cref="MinValue"/>
///
/// -or-
///
/// The resulting <see cref="DateTimeOffset"/> value is greater than <see cref="MaxValue"/>
/// </exception>
public DateTimeOffset AddMicroseconds(double microseconds) =>
new DateTimeOffset(ClockDateTime.AddMicroseconds(microseconds), Offset);

// Returns the DateTimeOffset resulting from adding a fractional number of
// minutes to this DateTimeOffset. The result is computed by rounding the
// fractional number of minutes given by value to the nearest
Expand Down
22 changes: 21 additions & 1 deletion src/libraries/System.Private.CoreLib/src/System/TimeOnly.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,17 @@ public TimeOnly(int hour, int minute, int second) : this(DateTime.TimeToTicks(ho
/// <param name="minute">The minutes (0 through 59).</param>
/// <param name="second">The seconds (0 through 59).</param>
/// <param name="millisecond">The millisecond (0 through 999).</param>
public TimeOnly(int hour, int minute, int second, int millisecond) : this(DateTime.TimeToTicks(hour, minute, second, millisecond)) {}
public TimeOnly(int hour, int minute, int second, int millisecond) : this(DateTime.TimeToTicks(hour, minute, second, millisecond)) { }

/// <summary>
/// Initializes a new instance of the <see cref="TimeOnly"/> structure to the specified hour, minute, second, and millisecond.
/// </summary>
/// <param name="hour">The hours (0 through 23).</param>
/// <param name="minute">The minutes (0 through 59).</param>
/// <param name="second">The seconds (0 through 59).</param>
/// <param name="millisecond">The millisecond (0 through 999).</param>
/// <param name="microsecond">The microsecond (0 through 999).</param>
public TimeOnly(int hour, int minute, int second, int millisecond, int microsecond) : this(DateTime.TimeToTicks(hour, minute, second, millisecond, microsecond)) { }

/// <summary>
/// Initializes a new instance of the TimeOnly structure using a specified number of ticks.
Expand Down Expand Up @@ -104,6 +114,16 @@ public TimeOnly(long ticks)
/// </summary>
public int Millisecond => new TimeSpan(_ticks).Milliseconds;

/// <summary>
/// Gets the microsecond component of the time represented by this instance.
/// </summary>
public int Microsecond => new TimeSpan(_ticks).Microseconds;

/// <summary>
/// Gets the nanosecond component of the time represented by this instance.
/// </summary>
public int Nanosecond => new TimeSpan(_ticks).Nanoseconds;

/// <summary>
/// Gets the number of ticks that represent the time of this instance.
/// </summary>
Expand Down
Loading