Decompiled source of SmartFormat Extensions Time v3.6.0

BepInEx/core/SmartFormat.Extensions.Time/netstandard2.1/SmartFormat.Extensions.Time.dll

Decompiled 6 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text.Json;
using System.Text.RegularExpressions;
using Microsoft.CodeAnalysis;
using SmartFormat.Core.Extensions;
using SmartFormat.Core.Formatting;
using SmartFormat.Core.Parsing;
using SmartFormat.Extensions.Time.Utilities;
using SmartFormat.Utilities;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("SmartFormat")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("Copyright 2011-2025 SmartFormat Project")]
[assembly: AssemblyDescription("This package is a SmartFormat extension for formatting System.DateTime, System.DateTimeOffset and System.TimeSpan types.\n\nSmartFormat is a lightweight text templating library written in C#.\nIt can format various data sources into a string with a minimal, intuitive syntax similar to string.Format.\nIt uses extensions to provide named placeholders, localization, pluralization, gender conjugation, and list and time formatting.\n        ")]
[assembly: AssemblyFileVersion("3.6.0")]
[assembly: AssemblyInformationalVersion("3.6.0+daaa16ddd5375a12657c63bcb5c08e74eca10b61")]
[assembly: AssemblyProduct("SmartFormat")]
[assembly: AssemblyTitle("SmartFormat.Extensions.Time")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/axuno/SmartFormat.git")]
[assembly: AssemblyVersion("3.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace SmartFormat.Extensions
{
	public class TimeFormatter : IFormatter
	{
		private string _fallbackLanguage = "en";

		[Obsolete("Use property \"Name\" instead", true)]
		[ExcludeFromCodeCoverage]
		public string[] Names { get; set; } = new string[3]
		{
			"timespan",
			"time",
			string.Empty
		};


		public string Name { get; set; } = "time";


		public bool CanAutoDetect { get; set; }

		public TimeSpanFormatOptions DefaultFormatOptions { get; set; }

		public string FallbackLanguage
		{
			get
			{
				return _fallbackLanguage;
			}
			set
			{
				if (value == string.Empty)
				{
					_fallbackLanguage = value;
					return;
				}
				if (CommonLanguagesTimeTextInfo.GetTimeTextInfo(value) != null)
				{
					_fallbackLanguage = value;
					return;
				}
				throw new ArgumentException("No TimeTextInfo found for language '" + value + "'.");
			}
		}

		[Obsolete("This property is not supported any more. Changed process to get or set the default culture.", true)]
		[ExcludeFromCodeCoverage]
		public string DefaultTwoLetterISOLanguageName { get; set; } = "en";


		public TimeFormatter()
		{
			DefaultFormatOptions = TimeSpanUtility.DefaultFormatOptions;
		}

		[Obsolete("This constructor is not required. Changed process to determine the default culture.", true)]
		[ExcludeFromCodeCoverage]
		public TimeFormatter(string defaultTwoLetterLanguageName)
		{
			if (CommonLanguagesTimeTextInfo.GetTimeTextInfo(defaultTwoLetterLanguageName) == null)
			{
				throw new ArgumentException("Language '" + defaultTwoLetterLanguageName + "' for defaultTwoLetterLanguageName is not implemented.");
			}
			DefaultTwoLetterISOLanguageName = defaultTwoLetterLanguageName;
			DefaultFormatOptions = TimeSpanUtility.DefaultFormatOptions;
		}

		public bool TryEvaluateFormat(IFormattingInfo formattingInfo)
		{
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			Format format = formattingInfo.Format;
			Placeholder placeholder = formattingInfo.Placeholder;
			if (string.IsNullOrEmpty((placeholder != null) ? placeholder.FormatterName : null))
			{
				return false;
			}
			object currentValue = formattingInfo.CurrentValue;
			if ((!(currentValue is TimeSpan) && !(currentValue is DateTime) && !(currentValue is DateTimeOffset)) || 1 == 0)
			{
				Format format2 = formattingInfo.Format;
				throw new FormattingException((format2 != null) ? format2.Items.FirstOrDefault() : null, "'TimeFormatter' can only process types of TimeSpan, DateTime, DateTimeOffset, " + $"but not '{formattingInfo.CurrentValue?.GetType()}'", 0);
			}
			IList<string> timeParts = GetTimeParts(formattingInfo);
			if (timeParts == null)
			{
				return false;
			}
			if (format != null && ((FormatItem)format).Length > 1 && format.HasNested)
			{
				format.Items.RemoveAt(0);
				formattingInfo.FormatAsChild(format, (object)timeParts);
				return true;
			}
			formattingInfo.Write(string.Join(" ", timeParts));
			return true;
		}

		private IList<string>? GetTimeParts(IFormattingInfo formattingInfo)
		{
			Format format = formattingInfo.Format;
			object currentValue = formattingInfo.CurrentValue;
			string text = formattingInfo.FormatterOptions.Trim();
			string text2 = ((format != null) ? ((FormatItem)format).RawText.Trim() : null) ?? string.Empty;
			bool flag = text != string.Empty && text2 == string.Empty;
			string formatString = (flag ? text : text2);
			TimeSpan? fromTime = GetFromTime(currentValue);
			if (!fromTime.HasValue)
			{
				return null;
			}
			TimeTextInfo timeTextInfo = GetTimeTextInfo(formattingInfo, flag);
			TimeSpanFormatOptions options = TimeSpanFormatOptionsConverter.Parse(formatString);
			return fromTime.Value.ToTimeParts(options, timeTextInfo);
		}

		private static TimeSpan? GetFromTime(object? current)
		{
			TimeSpan? result = null;
			if (!(current is TimeSpan value))
			{
				if (!(current is DateTime dateTime))
				{
					if (current is DateTimeOffset dateTimeOffset)
					{
						result = SystemTime.OffsetNow().UtcDateTime.Subtract(dateTimeOffset.UtcDateTime);
					}
				}
				else
				{
					result = SystemTime.Now().ToUniversalTime().Subtract(dateTime.ToUniversalTime());
				}
			}
			else
			{
				result = value;
			}
			return result;
		}

		private TimeTextInfo GetTimeTextInfo(IFormattingInfo formattingInfo, bool v2Compatibility)
		{
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			if (formattingInfo.FormatDetails.Provider?.GetFormat(typeof(TimeTextInfo)) is TimeTextInfo result)
			{
				return result;
			}
			TimeTextInfo timeTextInfo = CommonLanguagesTimeTextInfo.GetTimeTextInfo(GetCultureInfo(formattingInfo, v2Compatibility).TwoLetterISOLanguageName);
			if (timeTextInfo != null)
			{
				return timeTextInfo;
			}
			if (FallbackLanguage == string.Empty)
			{
				throw new FormattingException((FormatItem)(object)formattingInfo.Placeholder, "TimeTextInfo could not be found for the given culture argument '" + formattingInfo.FormatterOptions + "'.", 0);
			}
			if (FallbackLanguage != string.Empty)
			{
				return CommonLanguagesTimeTextInfo.GetTimeTextInfo(FallbackLanguage);
			}
			throw new ArgumentException("TimeTextInfo could not be found for the given IFormatProvider.", "formattingInfo");
		}

		private static CultureInfo GetCultureInfo(IFormattingInfo formattingInfo, bool v2Compatibility)
		{
			string text = ((!v2Compatibility) ? formattingInfo.FormatterOptions.Trim() : string.Empty);
			if (text == string.Empty)
			{
				if (formattingInfo.FormatDetails.Provider is CultureInfo result)
				{
					return result;
				}
				return CultureInfo.CurrentUICulture;
			}
			return CultureInfo.GetCultureInfo(text);
		}
	}
}
namespace SmartFormat.Extensions.Time.Utilities
{
	public static class CommonLanguagesTimeTextInfo
	{
		private static readonly Dictionary<string, TimeTextInfo> _customLanguage = new Dictionary<string, TimeTextInfo>();

		[Obsolete("Use GetTimeTextInfo(\"en\") instead")]
		[ExcludeFromCodeCoverage]
		public static TimeTextInfo English => GetTimeTextInfo("en");

		[Obsolete("Use GetTimeTextInfo(\"fr\") instead")]
		[ExcludeFromCodeCoverage]
		public static TimeTextInfo French => GetTimeTextInfo("fr");

		[Obsolete("Use GetTimeTextInfo(\"es\") instead")]
		[ExcludeFromCodeCoverage]
		public static TimeTextInfo Spanish => GetTimeTextInfo("es");

		[Obsolete("Use GetTimeTextInfo(\"pt\") instead")]
		[ExcludeFromCodeCoverage]
		public static TimeTextInfo Portuguese => GetTimeTextInfo("pt");

		[Obsolete("Use GetTimeTextInfo(\"it\") instead")]
		[ExcludeFromCodeCoverage]
		public static TimeTextInfo Italian => GetTimeTextInfo("it");

		[Obsolete("Use GetTimeTextInfo(\"de\") instead")]
		[ExcludeFromCodeCoverage]
		public static TimeTextInfo German => GetTimeTextInfo("de");

		public static void AddLanguage(string twoLetterIsoLanguageName, TimeTextInfo timeTextInfo)
		{
			string key = twoLetterIsoLanguageName.ToLower();
			_customLanguage.Add(key, timeTextInfo);
		}

		public static TimeTextInfo? GetTimeTextInfo(string twoLetterIsoLanguageName)
		{
			if (_customLanguage.TryGetValue(twoLetterIsoLanguageName, out TimeTextInfo value))
			{
				return value;
			}
			value = LoadTimeTextInfo(twoLetterIsoLanguageName);
			if (value == null)
			{
				return null;
			}
			_customLanguage.Add(twoLetterIsoLanguageName, value);
			return value;
		}

		private static TimeTextInfo? LoadTimeTextInfo(string languageCode)
		{
			Assembly executingAssembly = Assembly.GetExecutingAssembly();
			string name = "SmartFormat.Extensions.Time.Resources." + languageCode + ".json";
			using Stream stream = executingAssembly.GetManifestResourceStream(name);
			if (stream == null)
			{
				return null;
			}
			using StreamReader streamReader = new StreamReader(stream);
			TimeTextInfoData timeTextInfoData = JsonSerializer.Deserialize<TimeTextInfoData>(streamReader.ReadToEnd());
			return new TimeTextInfo
			{
				PluralRule = PluralRules.GetPluralRule(timeTextInfoData.PluralRule),
				Ptxt_week = timeTextInfoData.Ptxt_week,
				Ptxt_day = timeTextInfoData.Ptxt_day,
				Ptxt_hour = timeTextInfoData.Ptxt_hour,
				Ptxt_minute = timeTextInfoData.Ptxt_minute,
				Ptxt_second = timeTextInfoData.Ptxt_second,
				Ptxt_millisecond = timeTextInfoData.Ptxt_millisecond,
				Ptxt_w = timeTextInfoData.Ptxt_w,
				Ptxt_d = timeTextInfoData.Ptxt_d,
				Ptxt_h = timeTextInfoData.Ptxt_h,
				Ptxt_m = timeTextInfoData.Ptxt_m,
				Ptxt_s = timeTextInfoData.Ptxt_s,
				Ptxt_ms = timeTextInfoData.Ptxt_ms,
				Ptxt_lessThan = timeTextInfoData.Ptxt_lessThan
			};
		}
	}
	internal struct TimeTextInfoData
	{
		public string PluralRule { get; set; }

		public string[] Ptxt_week { get; set; }

		public string[] Ptxt_day { get; set; }

		public string[] Ptxt_hour { get; set; }

		public string[] Ptxt_minute { get; set; }

		public string[] Ptxt_second { get; set; }

		public string[] Ptxt_millisecond { get; set; }

		public string[] Ptxt_w { get; set; }

		public string[] Ptxt_d { get; set; }

		public string[] Ptxt_h { get; set; }

		public string[] Ptxt_m { get; set; }

		public string[] Ptxt_s { get; set; }

		public string[] Ptxt_ms { get; set; }

		public string Ptxt_lessThan { get; set; }
	}
	[Flags]
	public enum TimeSpanFormatOptions
	{
		None = 0,
		Abbreviate = 1,
		AbbreviateOff = 2,
		LessThan = 4,
		LessThanOff = 8,
		TruncateShortest = 0x10,
		TruncateAuto = 0x20,
		TruncateFill = 0x40,
		TruncateFull = 0x80,
		RangeMilliSeconds = 0x100,
		RangeSeconds = 0x200,
		RangeMinutes = 0x400,
		RangeHours = 0x800,
		RangeDays = 0x1000,
		RangeWeeks = 0x2000
	}
	internal static class TimeSpanFormatOptionsPresets
	{
		public const TimeSpanFormatOptions Abbreviate = TimeSpanFormatOptions.Abbreviate | TimeSpanFormatOptions.AbbreviateOff;

		public const TimeSpanFormatOptions LessThan = TimeSpanFormatOptions.LessThan | TimeSpanFormatOptions.LessThanOff;

		public const TimeSpanFormatOptions Truncate = TimeSpanFormatOptions.TruncateShortest | TimeSpanFormatOptions.TruncateAuto | TimeSpanFormatOptions.TruncateFill | TimeSpanFormatOptions.TruncateFull;

		public const TimeSpanFormatOptions Range = TimeSpanFormatOptions.RangeMilliSeconds | TimeSpanFormatOptions.RangeSeconds | TimeSpanFormatOptions.RangeMinutes | TimeSpanFormatOptions.RangeHours | TimeSpanFormatOptions.RangeDays | TimeSpanFormatOptions.RangeWeeks;
	}
	internal static class TimeSpanFormatOptionsConverter
	{
		[CompilerGenerated]
		private sealed class <AllFlags>d__3 : IEnumerable<TimeSpanFormatOptions>, IEnumerable, IEnumerator<TimeSpanFormatOptions>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private TimeSpanFormatOptions <>2__current;

			private int <>l__initialThreadId;

			private TimeSpanFormatOptions timeSpanFormatOptions;

			public TimeSpanFormatOptions <>3__timeSpanFormatOptions;

			private uint <value>5__2;

			TimeSpanFormatOptions IEnumerator<TimeSpanFormatOptions>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <AllFlags>d__3(int <>1__state)
			{
				this.<>1__state = <>1__state;
				<>l__initialThreadId = Environment.CurrentManagedThreadId;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				int num = <>1__state;
				if (num != 0)
				{
					if (num != 1)
					{
						return false;
					}
					<>1__state = -1;
					goto IL_004b;
				}
				<>1__state = -1;
				<value>5__2 = 1u;
				goto IL_0059;
				IL_004b:
				<value>5__2 <<= 1;
				goto IL_0059;
				IL_0059:
				if (<value>5__2 <= (uint)timeSpanFormatOptions)
				{
					if ((<value>5__2 & (uint)timeSpanFormatOptions) != 0)
					{
						<>2__current = (TimeSpanFormatOptions)<value>5__2;
						<>1__state = 1;
						return true;
					}
					goto IL_004b;
				}
				return false;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}

			[DebuggerHidden]
			IEnumerator<TimeSpanFormatOptions> IEnumerable<TimeSpanFormatOptions>.GetEnumerator()
			{
				<AllFlags>d__3 <AllFlags>d__;
				if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId)
				{
					<>1__state = 0;
					<AllFlags>d__ = this;
				}
				else
				{
					<AllFlags>d__ = new <AllFlags>d__3(0);
				}
				<AllFlags>d__.timeSpanFormatOptions = <>3__timeSpanFormatOptions;
				return <AllFlags>d__;
			}

			[DebuggerHidden]
			IEnumerator IEnumerable.GetEnumerator()
			{
				return ((IEnumerable<TimeSpanFormatOptions>)this).GetEnumerator();
			}
		}

		private static readonly Regex parser = new Regex("\\b(w|week|weeks|d|day|days|h|hour|hours|m|minute|minutes|s|second|seconds|ms|millisecond|milliseconds|auto|short|fill|full|abbr|noabbr|less|noless)\\b", RegexOptions.IgnoreCase | RegexOptions.Compiled, TimeSpan.FromMilliseconds(500.0));

		public static TimeSpanFormatOptions Merge(this TimeSpanFormatOptions left, TimeSpanFormatOptions right)
		{
			TimeSpanFormatOptions[] array = new TimeSpanFormatOptions[4]
			{
				TimeSpanFormatOptions.Abbreviate | TimeSpanFormatOptions.AbbreviateOff,
				TimeSpanFormatOptions.LessThan | TimeSpanFormatOptions.LessThanOff,
				TimeSpanFormatOptions.RangeMilliSeconds | TimeSpanFormatOptions.RangeSeconds | TimeSpanFormatOptions.RangeMinutes | TimeSpanFormatOptions.RangeHours | TimeSpanFormatOptions.RangeDays | TimeSpanFormatOptions.RangeWeeks,
				TimeSpanFormatOptions.TruncateShortest | TimeSpanFormatOptions.TruncateAuto | TimeSpanFormatOptions.TruncateFill | TimeSpanFormatOptions.TruncateFull
			};
			foreach (TimeSpanFormatOptions timeSpanFormatOptions in array)
			{
				if ((left & timeSpanFormatOptions) == 0)
				{
					left |= right & timeSpanFormatOptions;
				}
			}
			return left;
		}

		public static TimeSpanFormatOptions Mask(this TimeSpanFormatOptions timeSpanFormatOptions, TimeSpanFormatOptions mask)
		{
			return timeSpanFormatOptions & mask;
		}

		[IteratorStateMachine(typeof(<AllFlags>d__3))]
		public static IEnumerable<TimeSpanFormatOptions> AllFlags(this TimeSpanFormatOptions timeSpanFormatOptions)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <AllFlags>d__3(-2)
			{
				<>3__timeSpanFormatOptions = timeSpanFormatOptions
			};
		}

		public static TimeSpanFormatOptions Parse(string formatString)
		{
			formatString = formatString.ToLower();
			TimeSpanFormatOptions timeSpanFormatOptions = TimeSpanFormatOptions.None;
			IEnumerator enumerator = parser.Matches(formatString).GetEnumerator();
			try
			{
				while (enumerator.MoveNext())
				{
					switch (((Match)enumerator.Current).Value)
					{
					case "w":
					case "week":
					case "weeks":
						timeSpanFormatOptions |= TimeSpanFormatOptions.RangeWeeks;
						break;
					case "d":
					case "days":
					case "day":
						timeSpanFormatOptions |= TimeSpanFormatOptions.RangeDays;
						break;
					case "h":
					case "hour":
					case "hours":
						timeSpanFormatOptions |= TimeSpanFormatOptions.RangeHours;
						break;
					case "m":
					case "minute":
					case "minutes":
						timeSpanFormatOptions |= TimeSpanFormatOptions.RangeMinutes;
						break;
					case "s":
					case "second":
					case "seconds":
						timeSpanFormatOptions |= TimeSpanFormatOptions.RangeSeconds;
						break;
					case "ms":
					case "millisecond":
					case "milliseconds":
						timeSpanFormatOptions |= TimeSpanFormatOptions.RangeMilliSeconds;
						break;
					case "short":
						timeSpanFormatOptions |= TimeSpanFormatOptions.TruncateShortest;
						break;
					case "auto":
						timeSpanFormatOptions |= TimeSpanFormatOptions.TruncateAuto;
						break;
					case "fill":
						timeSpanFormatOptions |= TimeSpanFormatOptions.TruncateFill;
						break;
					case "full":
						timeSpanFormatOptions |= TimeSpanFormatOptions.TruncateFull;
						break;
					case "abbr":
						timeSpanFormatOptions |= TimeSpanFormatOptions.Abbreviate;
						break;
					case "noabbr":
						timeSpanFormatOptions |= TimeSpanFormatOptions.AbbreviateOff;
						break;
					case "less":
						timeSpanFormatOptions |= TimeSpanFormatOptions.LessThan;
						break;
					case "noless":
						timeSpanFormatOptions |= TimeSpanFormatOptions.LessThanOff;
						break;
					}
				}
				return timeSpanFormatOptions;
			}
			finally
			{
				IDisposable disposable = enumerator as IDisposable;
				if (disposable != null)
				{
					disposable.Dispose();
				}
			}
		}
	}
	public static class TimeSpanUtility
	{
		private static TimeSpanFormatOptions _rangeMin;

		private static TimeSpanFormatOptions _truncate;

		private static bool _lessThan;

		private static bool _abbreviate;

		private static Func<double, double>? _round;

		private static TimeTextInfo? _timeTextInfo;

		public static TimeSpanFormatOptions DefaultFormatOptions { get; set; }

		public static TimeSpanFormatOptions AbsoluteDefaults { get; }

		static TimeSpanUtility()
		{
			DefaultFormatOptions = TimeSpanFormatOptions.AbbreviateOff | TimeSpanFormatOptions.LessThan | TimeSpanFormatOptions.TruncateAuto | TimeSpanFormatOptions.RangeSeconds | TimeSpanFormatOptions.RangeDays;
			AbsoluteDefaults = DefaultFormatOptions;
		}

		public static string ToTimeString(this TimeSpan fromTime, TimeSpanFormatOptions options, TimeTextInfo timeTextInfo)
		{
			return string.Join(" ", fromTime.ToTimeParts(options, timeTextInfo));
		}

		internal static IList<string> ToTimeParts(this TimeSpan fromTime, TimeSpanFormatOptions options, TimeTextInfo timeTextInfo)
		{
			options = options.Merge(DefaultFormatOptions).Merge(AbsoluteDefaults);
			TimeSpanFormatOptions timeSpanFormatOptions = options.Mask(TimeSpanFormatOptions.RangeMilliSeconds | TimeSpanFormatOptions.RangeSeconds | TimeSpanFormatOptions.RangeMinutes | TimeSpanFormatOptions.RangeHours | TimeSpanFormatOptions.RangeDays | TimeSpanFormatOptions.RangeWeeks).AllFlags().Last();
			_rangeMin = options.Mask(TimeSpanFormatOptions.RangeMilliSeconds | TimeSpanFormatOptions.RangeSeconds | TimeSpanFormatOptions.RangeMinutes | TimeSpanFormatOptions.RangeHours | TimeSpanFormatOptions.RangeDays | TimeSpanFormatOptions.RangeWeeks).AllFlags().First();
			_truncate = options.Mask(TimeSpanFormatOptions.TruncateShortest | TimeSpanFormatOptions.TruncateAuto | TimeSpanFormatOptions.TruncateFill | TimeSpanFormatOptions.TruncateFull).AllFlags().First();
			_lessThan = options.Mask(TimeSpanFormatOptions.LessThan | TimeSpanFormatOptions.LessThanOff) != TimeSpanFormatOptions.LessThanOff;
			_abbreviate = options.Mask(TimeSpanFormatOptions.Abbreviate | TimeSpanFormatOptions.AbbreviateOff) != TimeSpanFormatOptions.AbbreviateOff;
			_round = (_lessThan ? new Func<double, double>(Math.Floor) : new Func<double, double>(Math.Ceiling));
			_timeTextInfo = timeTextInfo;
			switch (_rangeMin)
			{
			case TimeSpanFormatOptions.RangeWeeks:
				fromTime = TimeSpan.FromDays(_round(fromTime.TotalDays / 7.0) * 7.0);
				break;
			case TimeSpanFormatOptions.RangeDays:
				fromTime = TimeSpan.FromDays(_round(fromTime.TotalDays));
				break;
			case TimeSpanFormatOptions.RangeHours:
				fromTime = TimeSpan.FromHours(_round(fromTime.TotalHours));
				break;
			case TimeSpanFormatOptions.RangeMinutes:
				fromTime = TimeSpan.FromMinutes(_round(fromTime.TotalMinutes));
				break;
			case TimeSpanFormatOptions.RangeSeconds:
				fromTime = TimeSpan.FromSeconds(_round(fromTime.TotalSeconds));
				break;
			case TimeSpanFormatOptions.RangeMilliSeconds:
				fromTime = TimeSpan.FromMilliseconds(_round(fromTime.TotalMilliseconds));
				break;
			}
			List<string> list = new List<string>();
			for (TimeSpanFormatOptions timeSpanFormatOptions2 = timeSpanFormatOptions; timeSpanFormatOptions2 >= _rangeMin; timeSpanFormatOptions2 = (TimeSpanFormatOptions)((int)timeSpanFormatOptions2 >> 1))
			{
				int num;
				if (timeSpanFormatOptions2 <= TimeSpanFormatOptions.RangeMinutes)
				{
					if (timeSpanFormatOptions2 != TimeSpanFormatOptions.RangeMilliSeconds)
					{
						if (timeSpanFormatOptions2 != TimeSpanFormatOptions.RangeSeconds)
						{
							if (timeSpanFormatOptions2 != TimeSpanFormatOptions.RangeMinutes)
							{
								continue;
							}
							num = (int)Math.Floor(fromTime.TotalMinutes);
							fromTime -= TimeSpan.FromMinutes(num);
						}
						else
						{
							num = (int)Math.Floor(fromTime.TotalSeconds);
							fromTime -= TimeSpan.FromSeconds(num);
						}
					}
					else
					{
						num = (int)Math.Floor(fromTime.TotalMilliseconds);
						fromTime -= TimeSpan.FromMilliseconds(num);
					}
				}
				else if (timeSpanFormatOptions2 != TimeSpanFormatOptions.RangeHours)
				{
					if (timeSpanFormatOptions2 != TimeSpanFormatOptions.RangeDays)
					{
						if (timeSpanFormatOptions2 != TimeSpanFormatOptions.RangeWeeks)
						{
							continue;
						}
						num = (int)Math.Floor(fromTime.TotalDays / 7.0);
						fromTime -= TimeSpan.FromDays(num * 7);
					}
					else
					{
						num = (int)Math.Floor(fromTime.TotalDays);
						fromTime -= TimeSpan.FromDays(num);
					}
				}
				else
				{
					num = (int)Math.Floor(fromTime.TotalHours);
					fromTime -= TimeSpan.FromHours(num);
				}
				if (!ShouldTruncate(num, list.Count != 0, out var displayThisValue))
				{
					continue;
				}
				PrepareOutput(num, timeSpanFormatOptions2 == _rangeMin, list.Count != 0, list, ref displayThisValue);
				if (displayThisValue)
				{
					string unitText = _timeTextInfo.GetUnitText(timeSpanFormatOptions2, num, _abbreviate);
					if (!string.IsNullOrEmpty(unitText))
					{
						list.Add(unitText);
					}
				}
			}
			return list;
		}

		private static bool ShouldTruncate(int value, bool textStarted, out bool displayThisValue)
		{
			displayThisValue = false;
			switch (_truncate)
			{
			case TimeSpanFormatOptions.TruncateShortest:
				if (textStarted)
				{
					return false;
				}
				if (value > 0)
				{
					displayThisValue = true;
				}
				return true;
			case TimeSpanFormatOptions.TruncateAuto:
				if (value > 0)
				{
					displayThisValue = true;
				}
				return true;
			case TimeSpanFormatOptions.TruncateFill:
				if (textStarted || value > 0)
				{
					displayThisValue = true;
				}
				return true;
			case TimeSpanFormatOptions.TruncateFull:
				displayThisValue = true;
				return true;
			default:
				return false;
			}
		}

		private static void PrepareOutput(int value, bool isRangeMin, bool hasTextStarted, List<string> result, ref bool displayThisValue)
		{
			if (isRangeMin && !hasTextStarted)
			{
				displayThisValue = true;
				if (_lessThan && value < 1)
				{
					string unitText = _timeTextInfo.GetUnitText(_rangeMin, 1, _abbreviate);
					result.Add(_timeTextInfo.GetLessThanText(unitText));
					displayThisValue = false;
				}
			}
		}

		public static TimeSpan Round(this TimeSpan fromTime, long intervalTicks)
		{
			long num = fromTime.Ticks % intervalTicks;
			if (num >= intervalTicks >> 1)
			{
				num -= intervalTicks;
			}
			return TimeSpan.FromTicks(fromTime.Ticks - num);
		}
	}
	public class TimeTextInfo
	{
		public PluralRuleDelegate? PluralRule { get; set; }

		public string[] Ptxt_d { get; set; } = Array.Empty<string>();


		public string[] Ptxt_day { get; set; } = Array.Empty<string>();


		public string[] Ptxt_h { get; set; } = Array.Empty<string>();


		public string[] Ptxt_hour { get; set; } = Array.Empty<string>();


		public string Ptxt_lessThan { get; set; } = string.Empty;


		public string[] Ptxt_m { get; set; } = Array.Empty<string>();


		public string[] Ptxt_millisecond { get; set; } = Array.Empty<string>();


		public string[] Ptxt_minute { get; set; } = Array.Empty<string>();


		public string[] Ptxt_ms { get; set; } = Array.Empty<string>();


		public string[] Ptxt_s { get; set; } = Array.Empty<string>();


		public string[] Ptxt_second { get; set; } = Array.Empty<string>();


		public string[] Ptxt_w { get; set; } = Array.Empty<string>();


		public string[] Ptxt_week { get; set; } = Array.Empty<string>();


		private static string GetValue(PluralRuleDelegate pluralRule, int value, string[] units)
		{
			int num = ((units.Length != 1) ? pluralRule.Invoke((decimal)value, units.Length) : 0);
			return string.Format(units[num], value);
		}

		public virtual string GetLessThanText(string minimumValue)
		{
			return string.Format(Ptxt_lessThan, minimumValue);
		}

		public virtual string GetUnitText(TimeSpanFormatOptions unit, int value, bool abbr)
		{
			if (PluralRule == null)
			{
				throw new InvalidOperationException("Plural rule delegate must not be null");
			}
			return unit switch
			{
				TimeSpanFormatOptions.RangeWeeks => GetValue(PluralRule, value, abbr ? Ptxt_w : Ptxt_week), 
				TimeSpanFormatOptions.RangeDays => GetValue(PluralRule, value, abbr ? Ptxt_d : Ptxt_day), 
				TimeSpanFormatOptions.RangeHours => GetValue(PluralRule, value, abbr ? Ptxt_h : Ptxt_hour), 
				TimeSpanFormatOptions.RangeMinutes => GetValue(PluralRule, value, abbr ? Ptxt_m : Ptxt_minute), 
				TimeSpanFormatOptions.RangeSeconds => GetValue(PluralRule, value, abbr ? Ptxt_s : Ptxt_second), 
				TimeSpanFormatOptions.RangeMilliSeconds => GetValue(PluralRule, value, abbr ? Ptxt_ms : Ptxt_millisecond), 
				_ => string.Empty, 
			};
		}
	}
}