Skip to content

Commit 6769c92

Browse files
authored
Add support for Unix Epoch (#82)
1 parent 56e244c commit 6769c92

File tree

2 files changed

+68
-1
lines changed

2 files changed

+68
-1
lines changed

source/nanoFramework.CoreLibrary/System/AssemblyInfo2.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,4 @@
1414
[assembly: AssemblyProduct("nanoFramework mscorlib")]
1515
[assembly: AssemblyCopyright("Copyright © nanoFramework Contributors 2017")]
1616

17-
[assembly: AssemblyNativeVersion("1.2.0.0")]
17+
[assembly: AssemblyNativeVersion("1.2.1.0")]

source/nanoFramework.CoreLibrary/System/DateTime.cs

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,10 @@ public struct DateTime
9696
private const int MillisPerHour = MillisPerMinute * 60;
9797
private const int MillisPerDay = MillisPerHour * 24;
9898

99+
// Unix Epoch constants
100+
private const long UnixEpochTicks = (TicksPerDay * 719162) - _ticksAtOrigin; // 621355968000000000
101+
private const long UnixEpochSeconds = UnixEpochTicks / TicksPerSecond; // 62135596800
102+
99103
private const long MinTicks = 0;
100104
// ticks value corresponding to 3000/12/31:23:59:59.999
101105
private const long MaxTicks = 946708127999999999 - _ticksAtOrigin;
@@ -116,6 +120,14 @@ public struct DateTime
116120
/// </remarks>
117121
public static readonly DateTime MaxValue = new DateTime(MaxTicks + _ticksAtOrigin);
118122

123+
/// <summary>
124+
/// Represents the Unix Epoch value. This field is read-only.
125+
/// </summary>
126+
/// <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).
127+
/// This value is specific to nanoFramework.
128+
/// </remarks>
129+
public static readonly DateTime UnixEpoch = new DateTime(UnixEpochTicks + _ticksAtOrigin, DateTimeKind.Utc);
130+
119131
// The data is stored as an unsigned 64-bit integer
120132
// Bits 01-62: The value of 100-nanosecond ticks where 0 represents 1601/01/01:00:00:00.000, up until the value
121133
// 3000/12/31:23:59:59.999
@@ -701,6 +713,61 @@ public String ToString(String format)
701713
return Compare(t1, t2) >= 0;
702714
}
703715

716+
/// <summary>
717+
/// 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.
718+
/// </summary>
719+
/// <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>
720+
/// <returns>A date and time value that represents the same moment in time as the Unix time.</returns>
721+
/// <remarks>
722+
/// This method is exclusive of nanoFramework.
723+
/// </remarks>
724+
public static DateTime FromUnixTimeSeconds(long seconds)
725+
{
726+
const long MinSeconds = (MinTicks / TicksPerSecond) - UnixEpochSeconds;
727+
const long MaxSeconds = (MaxTicks / TicksPerSecond) - UnixEpochSeconds;
728+
729+
if (seconds < MinSeconds || seconds > MaxSeconds)
730+
{
731+
#pragma warning disable S3928 // Parameter names used into ArgumentException constructors should match an existing one
732+
throw new ArgumentOutOfRangeException();
733+
#pragma warning restore S3928 // Parameter names used into ArgumentException constructors should match an existing one
734+
}
735+
736+
long ticks = (seconds * TicksPerSecond) + UnixEpochTicks;
737+
return new DateTime(ticks + _ticksAtOrigin);
738+
}
739+
740+
/// <summary>
741+
/// Returns the number of seconds that have elapsed since 1970-01-01T00:00:00Z.
742+
/// </summary>
743+
/// <returns>The number of seconds that have elapsed since 1970-01-01T00:00:00Z.</returns>
744+
/// <remarks>
745+
/// 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.
746+
///
747+
/// This method is exclusive of nanoFramework.
748+
/// </remarks>
749+
public long ToUnixTimeSeconds()
750+
{
751+
// Truncate sub-second precision before offsetting by the Unix Epoch to avoid
752+
// the last digit being off by one for dates that result in negative Unix times.
753+
//
754+
// For example, consider the DateTime 12/31/1969 12:59:59.001 +0
755+
// ticks = 621355967990010000
756+
// ticksFromEpoch = ticks - UnixEpochTicks = -9990000
757+
// secondsFromEpoch = ticksFromEpoch / TicksPerSecond = 0
758+
//
759+
// Notice that secondsFromEpoch is rounded *up* by the truncation induced by integer division,
760+
// whereas we actually always want to round *down* when converting to Unix time. This happens
761+
// automatically for positive Unix time values. Now the example becomes:
762+
// seconds = ticks / TicksPerSecond = 62135596799
763+
// secondsFromEpoch = seconds - UnixEpochSeconds = -1
764+
//
765+
// In other words, we want to consistently round toward the time 1/1/0001 00:00:00,
766+
// rather than toward the Unix Epoch (1/1/1970 00:00:00).
767+
long seconds = (long)(_ticks / TicksPerSecond);
768+
return seconds - UnixEpochSeconds;
769+
}
770+
704771
/// <summary>
705772
/// Returns the hash code for this instance.
706773
/// </summary>

0 commit comments

Comments
 (0)