Skip to content

Commit

Permalink
Add support for Unix Epoch (#82)
Browse files Browse the repository at this point in the history
  • Loading branch information
josesimoes authored Jun 20, 2019
1 parent 56e244c commit 6769c92
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 1 deletion.
2 changes: 1 addition & 1 deletion source/nanoFramework.CoreLibrary/System/AssemblyInfo2.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@
[assembly: AssemblyProduct("nanoFramework mscorlib")]
[assembly: AssemblyCopyright("Copyright © nanoFramework Contributors 2017")]

[assembly: AssemblyNativeVersion("1.2.0.0")]
[assembly: AssemblyNativeVersion("1.2.1.0")]
67 changes: 67 additions & 0 deletions source/nanoFramework.CoreLibrary/System/DateTime.cs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,10 @@ public struct DateTime
private const int MillisPerHour = MillisPerMinute * 60;
private const int MillisPerDay = MillisPerHour * 24;

// Unix Epoch constants
private const long UnixEpochTicks = (TicksPerDay * 719162) - _ticksAtOrigin; // 621355968000000000
private const long UnixEpochSeconds = UnixEpochTicks / TicksPerSecond; // 62135596800

private const long MinTicks = 0;
// ticks value corresponding to 3000/12/31:23:59:59.999
private const long MaxTicks = 946708127999999999 - _ticksAtOrigin;
Expand All @@ -116,6 +120,14 @@ public struct DateTime
/// </remarks>
public static readonly DateTime MaxValue = new DateTime(MaxTicks + _ticksAtOrigin);

/// <summary>
/// Represents the Unix Epoch value. This field is read-only.
/// </summary>
/// <remarks>The value of this constant is equivalent to the <see cref="DateTime"/> corresponding to 1970-01-01T00:00:00Z (January 1, 1970, at 12:00 AM UTC).
/// This value is specific to nanoFramework.
/// </remarks>
public static readonly DateTime UnixEpoch = new DateTime(UnixEpochTicks + _ticksAtOrigin, DateTimeKind.Utc);

// The data is stored as an unsigned 64-bit integer
// Bits 01-62: The value of 100-nanosecond ticks where 0 represents 1601/01/01:00:00:00.000, up until the value
// 3000/12/31:23:59:59.999
Expand Down Expand Up @@ -701,6 +713,61 @@ public String ToString(String format)
return Compare(t1, t2) >= 0;
}

/// <summary>
/// Converts a Unix time expressed as the number of seconds that have elapsed since 1970-01-01T00:00:00Z to a <see cref="DateTime"/> value.
/// </summary>
/// <param name="seconds">A Unix time, expressed as the number of seconds that have elapsed since 1970-01-01T00:00:00Z (January 1, 1970, at 12:00 AM UTC). For Unix times before this date, its value is negative.</param>
/// <returns>A date and time value that represents the same moment in time as the Unix time.</returns>
/// <remarks>
/// This method is exclusive of nanoFramework.
/// </remarks>
public static DateTime FromUnixTimeSeconds(long seconds)
{
const long MinSeconds = (MinTicks / TicksPerSecond) - UnixEpochSeconds;
const long MaxSeconds = (MaxTicks / TicksPerSecond) - UnixEpochSeconds;

if (seconds < MinSeconds || seconds > MaxSeconds)
{
#pragma warning disable S3928 // Parameter names used into ArgumentException constructors should match an existing one
throw new ArgumentOutOfRangeException();
#pragma warning restore S3928 // Parameter names used into ArgumentException constructors should match an existing one
}

long ticks = (seconds * TicksPerSecond) + UnixEpochTicks;
return new DateTime(ticks + _ticksAtOrigin);
}

/// <summary>
/// Returns the number of seconds that have elapsed since 1970-01-01T00:00:00Z.
/// </summary>
/// <returns>The number of seconds that have elapsed since 1970-01-01T00:00:00Z.</returns>
/// <remarks>
/// Unix time represents the number of seconds that have elapsed since 1970-01-01T00:00:00Z (January 1, 1970, at 12:00 AM UTC). It does not take leap seconds into account.
///
/// This method is exclusive of nanoFramework.
/// </remarks>
public long ToUnixTimeSeconds()
{
// Truncate sub-second precision before offsetting by the Unix Epoch to avoid
// the last digit being off by one for dates that result in negative Unix times.
//
// For example, consider the DateTime 12/31/1969 12:59:59.001 +0
// ticks = 621355967990010000
// ticksFromEpoch = ticks - UnixEpochTicks = -9990000
// secondsFromEpoch = ticksFromEpoch / TicksPerSecond = 0
//
// Notice that secondsFromEpoch is rounded *up* by the truncation induced by integer division,
// whereas we actually always want to round *down* when converting to Unix time. This happens
// automatically for positive Unix time values. Now the example becomes:
// seconds = ticks / TicksPerSecond = 62135596799
// secondsFromEpoch = seconds - UnixEpochSeconds = -1
//
// In other words, we want to consistently round toward the time 1/1/0001 00:00:00,
// rather than toward the Unix Epoch (1/1/1970 00:00:00).
long seconds = (long)(_ticks / TicksPerSecond);
return seconds - UnixEpochSeconds;
}

/// <summary>
/// Returns the hash code for this instance.
/// </summary>
Expand Down

0 comments on commit 6769c92

Please sign in to comment.