value · System

DateTime

public value DateTime : IHashable<DateTime>, IComparable<DateTime>

A moment on the calendar, from 0001-01-01 to 9999-12-31, to 100 ns, and whose clock it reads (Kind). date + span, date - span, a - b (a TimeSpan) and the comparisons work on it; as text it is MM/dd/yyyy HH:mm:ss, and ToString("o") gives the round-trip form.

Kind
value
Namespace
System
Assembly
System.Core
Access
public
Source file
Time.ant

Inheritance

Interfaces
IHashable<TSelf> IComparable<TSelf>

Constructors

new(i64 ticks)
#

Ticks since 0001-01-01 00:00:00.

new(i64 ticks, DateTimeKind kind)
#
new(i32 year, i32 month, i32 day)
#
new(i32 year, i32 month, i32 day, i32 hour, i32 minute, i32 second)
#
new(i32 year, i32 month, i32 day, i32 hour, i32 minute, i32 second, DateTimeKind kind)
#
new(i32 year, i32 month, i32 day, i32 hour, i32 minute, i32 second, i32 millisecond)
#
new(i32 year, i32 month, i32 day, i32 hour, i32 minute, i32 second, i32 millisecond, DateTimeKind kind)
#

Properties

static DateTime MinValue { get; }
#

static read-only

static DateTime MaxValue { get; }
#

static read-only

static DateTime UnixEpoch { get; }
#

static read-only

1970-01-01 00:00:00 UTC.

static DateTime UtcNow { get; }
#

static read-only

Now: in UTC, in the local time zone, and today's date (local, at midnight).

static DateTime Now { get; }
#

static read-only

static DateTime Today { get; }
#

static read-only

i64 Ticks { get; }
#

read-only

DateTimeKind Kind { get; }
#

read-only

i32 Year { get; }
#

read-only

i32 Month { get; }
#

read-only

i32 Day { get; }
#

read-only

i32 Hour { get; }
#

read-only

i32 Minute { get; }
#

read-only

i32 Second { get; }
#

read-only

i32 Millisecond { get; }
#

read-only

i32 Microsecond { get; }
#

read-only

i32 Nanosecond { get; }
#

read-only

DayOfWeek DayOfWeek { get; }
#

read-only

i32 DayOfYear { get; }
#

read-only

1 for January 1st.

DateTime Date { get; }
#

read-only

The date at midnight (same kind), and the time since midnight.

TimeSpan TimeOfDay { get; }
#

read-only

Methods

static IsLeapYear(i32 year) : bool
#

static

static DaysInMonth(i32 year, i32 month) : i32
#

static

static SpecifyKind(DateTime value, DateTimeKind kind) : DateTime
#

static

The same moment with another kind (the clock reading is not changed).

Add(TimeSpan span) : DateTime
#
AddTicks(i64 value) : DateTime
#
AddDays(f64 value) : DateTime
#
AddHours(f64 value) : DateTime
#
AddMinutes(f64 value) : DateTime
#
AddSeconds(f64 value) : DateTime
#
AddMilliseconds(f64 value) : DateTime
#
AddMicroseconds(f64 value) : DateTime
#
AddMonths(i32 months) : DateTime
#

months months later: the same day, or the month's last day when it is shorter.

AddYears(i32 years) : DateTime
#
Subtract(DateTime other) : TimeSpan
#

The time from other to this moment, and this moment span earlier.

Subtract(TimeSpan span) : DateTime
#
Equals(DateTime other) : bool
#

The same moment (the kind is not compared).

Hash() : u64
#
CompareTo(DateTime other) : i32
#
static Compare(DateTime a, DateTime b) : i32
#

static

ToUniversalTime() : DateTime
#

The moment on UTC's clock and on the local time zone's (Unspecified counts as the other one).

ToLocalTime() : DateTime
#
ToUnixTimeSeconds() : i64
#

Seconds and milliseconds since 1970-01-01 UTC (Unspecified counts as UTC), and the UTC moment of a count of them.

ToUnixTimeMilliseconds() : i64
#
static FromUnixTimeSeconds(i64 seconds) : DateTime
#

static

static FromUnixTimeMilliseconds(i64 milliseconds) : DateTime
#

static

ToString() : str
#

MM/dd/yyyy HH:mm:ss.

ToString(str format) : str
#

As text by a format: a standard one (d, D, f, F, g, G, M, o, R, s, t, T, u, U, Y) or a custom one of yyyy, yy, MMMM, MMM, MM, M, dddd, ddd, dd, d, HH, H, hh, h, mm, m, ss, s, f…, F…, tt, t, K, zzz, zz, z, 'text', "text" and \x.

static Parse(str text) : DateTime
#

static

The moment text writes: ISO 8601 (2024-05-01, 2024-05-01T13:45:30.5Z, …+02:00), the invariant culture's 05/01/2024 1:45 PM, Wed, 01 May 2024 13:45:30 GMT, 1 May 2024, May 1, 2024, or a time alone (today); a FormatError when it writes none.

static Parse(str text, DateTimeStyles styles) : DateTime
#

static

static ParseExact(str text, str format) : DateTime
#

static

The moment text writes in exactly format (a standard or custom format, as ToString takes).

static ParseExact(str text, str format, DateTimeStyles styles) : DateTime
#

static

static TryParse(str text) : DateTime?
#

static

The moment, or null when text writes none.

static TryParse(str text, DateTimeStyles styles) : DateTime?
#

static

static TryParseExact(str text, str format) : DateTime?
#

static

static TryParseExact(str text, str format, DateTimeStyles styles) : DateTime?
#

static

ToBinary() : i64
#

The bits (ticks and kind), and a DateTime from them.

static FromBinary(i64 bits) : DateTime
#

static

Operators and conversions

op +(DateTime d, TimeSpan span) : DateTime
#

static

op -(DateTime d, TimeSpan span) : DateTime
#

static

op -(DateTime a, DateTime b) : TimeSpan
#

static

op ==(DateTime a, DateTime b) : bool
#

static

op !=(DateTime a, DateTime b) : bool
#

static

op <(DateTime a, DateTime b) : bool
#

static

op <=(DateTime a, DateTime b) : bool
#

static

op >(DateTime a, DateTime b) : bool
#

static

op >=(DateTime a, DateTime b) : bool
#

static

Private and internal members (7)

u64 data
#

private

static OutOfRange(i32 which)
#

private static

Throws an ArgumentOutOfRangeError: the message is made here, so the fast paths that may throw allocate nothing.

static Of(u64 data) : DateTime
#

private static

A DateTime from its bits (ticks already checked).

static DateTicks(i32 year, i32 month, i32 day) : i64
#

private static

The ticks of a date (checked), as .NET's DateToTicks.

static TimeTicks(i32 hour, i32 minute, i32 second) : i64
#

private static

Moved(i64 value) : DateTime
#

private

This moment value ticks later (an ArgumentOutOfRangeError past the calendar's ends).

AddUnits(f64 value, i64 most, i64 scale) : DateTime
#

private

value units of scale ticks later: whole units exactly, the fraction rounded toward zero.

Source

DateTime as Antril, decompiled from its Larva HIR.

System.DateTime.ant
// System.DateTime — System.Core (decompiled from Larva HIR)

into namespace System
{
	/// A moment on the calendar, from 0001-01-01 to 9999-12-31, to 100 ns, and whose clock it reads (Kind).
	/// `date + span`, `date - span`, `a - b` (a TimeSpan) and the comparisons work on it; as text it is
	/// `MM/dd/yyyy HH:mm:ss`, and ToString("o") gives the round-trip form.
	public value DateTime : IHashable<DateTime>, IComparable<DateTime>
	{
		u64 data;

		/// Throws an ArgumentOutOfRangeError: the message is made here, so the fast paths that may throw allocate nothing.
		[NoInline]
		static OutOfRange(i32 which)
		{
			str what = which switch { 0 => "the year, month and day make no date", 1 => "the hour, minute and second make no time", 2 => "the result is outside the calendar", 3 => "the ticks are outside the calendar", 4 => "the millisecond is not 0-999", 5 => "the year is not 1-9999", 6 => "the month is not 1-12", 7 => "the months are not -120000-120000", 8 => "the years are not -10000-10000", 9 => "the seconds are outside the calendar", 10 => "the milliseconds are outside the calendar", 11 => "the bits make no DateTime", _ => "the value is out of range" };
			throw new ArgumentOutOfRangeError("DateTime: " + what);
		}

		/// A DateTime from its bits (ticks already checked).
		static Of(u64 data) : DateTime
		{
			DateTime made = new DateTime(0);
			made.data = data;
			return made;
		}

		/// The ticks of a date (checked), as .NET's DateToTicks.
		static DateTicks(i32 year, i32 month, i32 day) : i64
		{
			if ((u32)(year - 1) >= 9999 || (u32)(month - 1) >= 12 || (u32)(day - 1) >= 28 && (day < 1 || day > Dates.MonthLength(year, month)))
				OutOfRange(0);
			return Dates.DaysOf(year, month, day) * 864000000000;
		}

		static TimeTicks(i32 hour, i32 minute, i32 second) : i64
		{
			if ((u32)hour >= 24 || (u32)minute >= 60 || (u32)second >= 60)
				OutOfRange(1);
			return ((i64)hour * 3600 + (i64)minute * 60 + (i64)second) * 10000000;
		}

		/// This moment `value` ticks later (an ArgumentOutOfRangeError past the calendar's ends).
		Moved(i64 value) : DateTime
		{
			i64 ticks = (i64)(data & 4611686018427387903);
			if (value > 3155378975999999999 - ticks || value < -ticks)
				OutOfRange(2);
			return Of((u64)(ticks + value) | data & 13835058055282163712);
		}

		/// `value` units of `scale` ticks later: whole units exactly, the fraction rounded toward zero.
		AddUnits(f64 value, i64 most, i64 scale) : DateTime
		{
			if (!(value <= most && value >= -(f64)most))
				OutOfRange(2);
			i64 whole = (i64)value;
			f64 fraction = value - (f64)whole;
			return Moved(whole * scale + (i64)(fraction * (f64)scale));
		}

		public:
			/// Ticks since 0001-01-01 00:00:00.
			new(i64 ticks)
			{
				if ((u64)ticks > 3155378975999999999)
					OutOfRange(3);
				data = (u64)ticks;
			}

			new(i64 ticks, DateTimeKind kind)
			{
				if ((u64)ticks > 3155378975999999999)
					OutOfRange(3);
				data = (u64)ticks | (u64)(i32)kind << 62;
			}

			new(i32 year, i32 month, i32 day)
			{
				data = (u64)DateTicks(year, month, day);
			}

			new(i32 year, i32 month, i32 day, i32 hour, i32 minute, i32 second)
			{
				data = (u64)(DateTicks(year, month, day) + TimeTicks(hour, minute, second));
			}

			new(i32 year, i32 month, i32 day, i32 hour, i32 minute, i32 second, DateTimeKind kind)
			{
				data = (u64)(DateTicks(year, month, day) + TimeTicks(hour, minute, second)) | (u64)(i32)kind << 62;
			}

			new(i32 year, i32 month, i32 day, i32 hour, i32 minute, i32 second, i32 millisecond)
			{
				if ((u32)millisecond >= 1000)
					OutOfRange(4);
				data = (u64)(DateTicks(year, month, day) + TimeTicks(hour, minute, second) + (i64)millisecond * 10000);
			}

			new(i32 year, i32 month, i32 day, i32 hour, i32 minute, i32 second, i32 millisecond, DateTimeKind kind)
			{
				if ((u32)millisecond >= 1000)
					OutOfRange(4);
				data = (u64)(DateTicks(year, month, day) + TimeTicks(hour, minute, second) + (i64)millisecond * 10000) | (u64)(i32)kind << 62;
			}

			static IsLeapYear(i32 year) : bool
			{
				if (year < 1 || year > 9999)
					OutOfRange(5);
				return (year & 3) == 0 && (year % 100 != 0 || year % 400 == 0);
			}

			static DaysInMonth(i32 year, i32 month) : i32
			{
				if (month < 1 || month > 12)
					OutOfRange(6);
				if (month == 2)
					return IsLeapYear(year) ? 29 : 28;
				return 30 + (month + (month >> 3) & 1);
			}

			/// The same moment with another kind (the clock reading is not changed).
			static SpecifyKind(DateTime value, DateTimeKind kind) : DateTime => Of(value.data & 4611686018427387903 | (u64)(i32)kind << 62);

			Add(TimeSpan span) : DateTime => Moved(span.Ticks);

			AddTicks(i64 value) : DateTime => Moved(value);

			AddDays(f64 value) : DateTime => AddUnits(value, 10000000, 864000000000);

			AddHours(f64 value) : DateTime => AddUnits(value, 240000000, 36000000000);

			AddMinutes(f64 value) : DateTime => AddUnits(value, 14400000000, 600000000);

			AddSeconds(f64 value) : DateTime => AddUnits(value, 864000000000, 10000000);

			AddMilliseconds(f64 value) : DateTime => AddUnits(value, 864000000000000, 10000);

			AddMicroseconds(f64 value) : DateTime => AddUnits(value, 864000000000000000, 10);

			/// `months` months later: the same day, or the month's last day when it is shorter.
			AddMonths(i32 months) : DateTime
			{
				if (months < -120000 || months > 120000)
					OutOfRange(7);
				u64 ticks = data & 4611686018427387903;
				u32 parts = Dates.Parts(ticks);
				i32 year = (i32)(parts >> 9);
				i32 month = (i32)(parts >> 5 & 15);
				i32 day = (i32)(parts & 31);
				i32 at = month - 1 + months;
				if (at >= 0)
				{
					month = at % 12 + 1;
					year += at / 12;
				}
				else
				{
					month = 12 + (at + 1) % 12;
					year += (at - 11) / 12;
				}
				if (year < 1 || year > 9999)
					OutOfRange(2);
				if (day > 28)
				{
					i32 last = Dates.MonthLength(year, month);
					if (day > last)
						day = last;
				}
				return Of((u64)(Dates.DaysOf(year, month, day) * 864000000000) + ticks % 864000000000 | data & 13835058055282163712);
			}

			AddYears(i32 years) : DateTime
			{
				if (years < -10000 || years > 10000)
					OutOfRange(8);
				return AddMonths(years * 12);
			}

			/// The time from `other` to this moment, and this moment `span` earlier.
			Subtract(DateTime other) : TimeSpan => new TimeSpan(Ticks - other.Ticks);

			Subtract(TimeSpan span) : DateTime
			{
				if (span.Ticks == -9223372036854775808)
					OutOfRange(2);
				return Moved(-span.Ticks);
			}

			op +(DateTime d, TimeSpan span) : DateTime => d.Moved(span.Ticks);

			op -(DateTime d, TimeSpan span) : DateTime => d.Subtract(span);

			op -(DateTime a, DateTime b) : TimeSpan => new TimeSpan(a.Ticks - b.Ticks);

			op ==(DateTime a, DateTime b) : bool => ((a.data ^ b.data) & 4611686018427387903) == 0;

			op !=(DateTime a, DateTime b) : bool => ((a.data ^ b.data) & 4611686018427387903) != 0;

			op <(DateTime a, DateTime b) : bool => (a.data & 4611686018427387903) < (b.data & 4611686018427387903);

			op <=(DateTime a, DateTime b) : bool => (a.data & 4611686018427387903) <= (b.data & 4611686018427387903);

			op >(DateTime a, DateTime b) : bool => (a.data & 4611686018427387903) > (b.data & 4611686018427387903);

			op >=(DateTime a, DateTime b) : bool => (a.data & 4611686018427387903) >= (b.data & 4611686018427387903);

			/// The same moment (the kind is not compared).
			Equals(DateTime other) : bool => ((data ^ other.data) & 4611686018427387903) == 0;

			Hash() : u64 => (data & 4611686018427387903) * 11400714819323198485;

			CompareTo(DateTime other) : i32
			{
				u64 a = data & 4611686018427387903;
				u64 b = other.data & 4611686018427387903;
				return a < b ? -1 : a > b ? 1 : 0;
			}

			static Compare(DateTime a, DateTime b) : i32 => a.CompareTo(b);

			/// The moment on UTC's clock and on the local time zone's (Unspecified counts as the other one).
			ToUniversalTime() : DateTime
			{
				if (data >> 62 == 1)
					return this;
				i64 local = Ticks;
				i64 utc = local - LocalZone.OffsetOfLocal(local);
				if (utc < 0)
					utc = 0;
				if (utc > 3155378975999999999)
					utc = 3155378975999999999;
				return Of((u64)utc | 4611686018427387904);
			}

			ToLocalTime() : DateTime
			{
				if (data >> 62 == 2)
					return this;
				i64 utc = Ticks;
				i64 local = utc + LocalZone.Offset(utc);
				if (local < 0)
					local = 0;
				if (local > 3155378975999999999)
					local = 3155378975999999999;
				return Of((u64)local | 9223372036854775808);
			}

			/// Seconds and milliseconds since 1970-01-01 UTC (Unspecified counts as UTC), and the UTC moment of a count of
			/// them.
			ToUnixTimeSeconds() : i64
			{
				i64 ticks = data >> 62 == 2 ? ToUniversalTime().Ticks : Ticks;
				i64 seconds = ticks / 10000000 - 62135596800;
				return seconds;
			}

			ToUnixTimeMilliseconds() : i64
			{
				i64 ticks = data >> 62 == 2 ? ToUniversalTime().Ticks : Ticks;
				return ticks / 10000 - 62135596800000;
			}

			static FromUnixTimeSeconds(i64 seconds) : DateTime
			{
				if (seconds < -62135596800 || seconds > 253402300799)
					OutOfRange(9);
				return Of((u64)((seconds + 62135596800) * 10000000) | 4611686018427387904);
			}

			static FromUnixTimeMilliseconds(i64 milliseconds) : DateTime
			{
				if (milliseconds < -62135596800000 || milliseconds > 253402300799999)
					OutOfRange(10);
				return Of((u64)((milliseconds + 62135596800000) * 10000) | 4611686018427387904);
			}

			/// `MM/dd/yyyy HH:mm:ss`.
			ToString() : str => TimeFormat.General(this);

			/// As text by a format: a standard one (d, D, f, F, g, G, M, o, R, s, t, T, u, U, Y) or a custom one of
			/// yyyy, yy, MMMM, MMM, MM, M, dddd, ddd, dd, d, HH, H, hh, h, mm, m, ss, s, f…, F…, tt, t, K, zzz, zz, z,
			/// 'text', "text" and \x.
			ToString(str format) : str => TimeFormat.Date(this, format);

			/// The moment `text` writes: ISO 8601 (`2024-05-01`, `2024-05-01T13:45:30.5Z`, `…+02:00`), the invariant
			/// culture's `05/01/2024 1:45 PM`, `Wed, 01 May 2024 13:45:30 GMT`, `1 May 2024`, `May 1, 2024`, or a time
			/// alone (today); a FormatError when it writes none.
			static Parse(str text) : DateTime => Parse(text, DateTimeStyles.None);

			static Parse(str text, DateTimeStyles styles) : DateTime
			{
				DateTime? read = TimeFormat.ReadDate(text, null, styles);
				if (read == null)
					TimeFormat.NotADate(text);
				return read.Value;
			}

			/// The moment `text` writes in exactly `format` (a standard or custom format, as ToString takes).
			static ParseExact(str text, str format) : DateTime => ParseExact(text, format, DateTimeStyles.None);

			static ParseExact(str text, str format, DateTimeStyles styles) : DateTime
			{
				DateTime? read = TimeFormat.ReadDate(text, format, styles);
				if (read == null)
					TimeFormat.NotADate(text);
				return read.Value;
			}

			/// The moment, or null when `text` writes none.
			static TryParse(str text) : DateTime? => TimeFormat.ReadDate(text, null, DateTimeStyles.None);

			static TryParse(str text, DateTimeStyles styles) : DateTime? => TimeFormat.ReadDate(text, null, styles);

			static TryParseExact(str text, str format) : DateTime? => TimeFormat.ReadDate(text, format, DateTimeStyles.None);

			static TryParseExact(str text, str format, DateTimeStyles styles) : DateTime? => TimeFormat.ReadDate(text, format, styles);

			/// The bits (ticks and kind), and a DateTime from them.
			ToBinary() : i64 => (i64)data;

			static FromBinary(i64 bits) : DateTime
			{
				if (((u64)bits & 4611686018427387903) > 3155378975999999999 || (u64)bits >> 62 == 3)
					OutOfRange(11);
				return Of((u64)bits);
			}

			static DateTime MinValue
			{
				get => Of(0);
			}

			static DateTime MaxValue
			{
				get => Of(3155378975999999999);
			}

			/// 1970-01-01 00:00:00 UTC.
			static DateTime UnixEpoch
			{
				get => Of(5233041986427387904);
			}

			/// Now: in UTC, in the local time zone, and today's date (local, at midnight).
			static DateTime UtcNow
			{
				get => Of((u64)(Dates.Clock() + 621355968000000000) | 4611686018427387904);
			}

			static DateTime Now
			{
				get
				{
					i64 utc = Dates.Clock() + 621355968000000000;
					return Of((u64)(utc + LocalZone.Offset(utc)) | 9223372036854775808);
				}
			}

			static DateTime Today
			{
				get => Now.Date;
			}

			i64 Ticks
			{
				get => (i64)(data & 4611686018427387903);
			}

			DateTimeKind Kind
			{
				get => (DateTimeKind)(i32)(data >> 62);
			}

			i32 Year
			{
				get => Dates.YearOf(data & 4611686018427387903);
			}

			i32 Month
			{
				get => (i32)(Dates.Parts(data & 4611686018427387903) >> 5 & 15);
			}

			i32 Day
			{
				get => (i32)(Dates.Parts(data & 4611686018427387903) & 31);
			}

			i32 Hour
			{
				get => (i32)((data & 4611686018427387903) / 36000000000 % 24);
			}

			i32 Minute
			{
				get => (i32)((data & 4611686018427387903) / 600000000 % 60);
			}

			i32 Second
			{
				get => (i32)((data & 4611686018427387903) / 10000000 % 60);
			}

			i32 Millisecond
			{
				get => (i32)((data & 4611686018427387903) / 10000 % 1000);
			}

			i32 Microsecond
			{
				get => (i32)((data & 4611686018427387903) / 10 % 1000);
			}

			i32 Nanosecond
			{
				get => (i32)((data & 4611686018427387903) % 10) * 100;
			}

			DayOfWeek DayOfWeek
			{
				get => (DayOfWeek)(i32)(((data & 4611686018427387903) / 864000000000 + 1) % 7);
			}

			/// 1 for January 1st.
			i32 DayOfYear
			{
				get
				{
					u32 quarters = (u32)((data & 4611686018427387903) / 216000000000) | 3;
					u32 rest = quarters % 146097 | 3;
					u32 scaled = rest * 2939745;
					return (i32)(scaled / 11758980) + 1;
				}
			}

			/// The date at midnight (same kind), and the time since midnight.
			DateTime Date
			{
				get => Of(data - (data & 4611686018427387903) % 864000000000);
			}

			TimeSpan TimeOfDay
			{
				get => new TimeSpan((i64)((data & 4611686018427387903) % 864000000000));
			}
	}
}
Esc