public SortedDictionary <string, object> DateTimeResolution(DateTimeParseResult slot)
        {
            if (slot == null)
            {
                return(null);
            }

            var resolutions = new List <Dictionary <string, string> >();
            var res         = new Dictionary <string, object>();

            var type  = slot.Type;
            var timex = slot.TimexStr;

            var val = (DateTimeResolutionResult)slot.Value;

            if (val == null)
            {
                return(null);
            }

            var    isLunar = val.IsLunar;
            var    mod     = val.Mod;
            string list    = null;

            // Resolve dates list for date periods
            if (slot.Type.Equals(Constants.SYS_DATETIME_DATEPERIOD, StringComparison.Ordinal) && val.List != null)
            {
                list = string.Join(",", val.List.Select(o => DateTimeFormatUtil.LuisDate((DateObject)o)).ToArray());
            }

            // With modifier, output Type might not be the same with type in resolution result
            // For example, if the resolution type is "date", with modifier the output type should be "daterange"
            var typeOutput = DetermineDateTimeType(slot.Type, hasMod: !string.IsNullOrEmpty(mod));

            var sourceEntity = DetermineSourceEntityType(slot.Type, typeOutput, val.HasRangeChangingMod);

            var comment = val.Comment;

            // The following should be added to res first, since ResolveAmPm requires these fields.
            AddResolutionFields(res, DateTimeResolutionKey.Timex, timex);
            AddResolutionFields(res, Constants.Comment, comment);
            AddResolutionFields(res, DateTimeResolutionKey.Mod, mod);
            AddResolutionFields(res, ResolutionKey.Type, typeOutput);
            AddResolutionFields(res, DateTimeResolutionKey.IsLunar, isLunar ? isLunar.ToString(CultureInfo.InvariantCulture) : string.Empty);

            var hasTimeZone = false;

            // For standalone timezone entity recognition, we generate TimeZoneResolution for each entity we extracted.
            // We also merge time entity with timezone entity and add the information in TimeZoneResolution to every DateTime resolutions.
            if (val.TimeZoneResolution != null)
            {
                if (slot.Type.Equals(Constants.SYS_DATETIME_TIMEZONE, StringComparison.Ordinal))
                {
                    // single timezone
                    AddResolutionFields(res, Constants.ResolveTimeZone, new Dictionary <string, string>
                    {
                        { ResolutionKey.Value, val.TimeZoneResolution.Value },
                        { Constants.UtcOffsetMinsKey, val.TimeZoneResolution.UtcOffsetMins.ToString(CultureInfo.InvariantCulture) },
                    });
                }
                else
                {
                    // timezone as clarification of datetime
                    hasTimeZone = true;
                    AddResolutionFields(res, Constants.TimeZone, val.TimeZoneResolution.Value);
                    AddResolutionFields(res, Constants.TimeZoneText, val.TimeZoneResolution.TimeZoneText);
                    AddResolutionFields(res, Constants.UtcOffsetMinsKey,
                                        val.TimeZoneResolution.UtcOffsetMins.ToString(CultureInfo.InvariantCulture));
                }
            }

            var pastResolutionStr   = ((DateTimeResolutionResult)slot.Value).PastResolution;
            var futureResolutionStr = ((DateTimeResolutionResult)slot.Value).FutureResolution;

            if (typeOutput == Constants.SYS_DATETIME_DATETIMEALT && pastResolutionStr.Count > 0)
            {
                typeOutput = DetermineResolutionDateTimeType(pastResolutionStr);
            }

            var resolutionPast   = GenerateResolution(type, pastResolutionStr, mod);
            var resolutionFuture = GenerateResolution(type, futureResolutionStr, mod);

            // If past and future are same, keep only one
            if (resolutionFuture.OrderBy(t => t.Key).Select(t => t.Value)
                .SequenceEqual(resolutionPast.OrderBy(t => t.Key).Select(t => t.Value)))
            {
                if (resolutionPast.Count > 0)
                {
                    AddResolutionFields(res, Constants.Resolve, resolutionPast);
                }
            }
            else
            {
                if (resolutionPast.Count > 0)
                {
                    AddResolutionFields(res, Constants.ResolveToPast, resolutionPast);
                }

                if (resolutionFuture.Count > 0)
                {
                    AddResolutionFields(res, Constants.ResolveToFuture, resolutionFuture);
                }
            }

            // If 'ampm', double our resolution accordingly
            if (!string.IsNullOrEmpty(comment) && comment.Equals(Constants.Comment_AmPm, StringComparison.Ordinal))
            {
                if (res.ContainsKey(Constants.Resolve))
                {
                    ResolveAmpm(res, Constants.Resolve);
                }
                else
                {
                    ResolveAmpm(res, Constants.ResolveToPast);
                    ResolveAmpm(res, Constants.ResolveToFuture);
                }
            }

            // If WeekOf and in CalendarMode, modify the past part of our resolution
            if ((Config.Options & DateTimeOptions.CalendarMode) != 0 &&
                !string.IsNullOrEmpty(comment) && comment.Equals(Constants.Comment_WeekOf, StringComparison.Ordinal))
            {
                ResolveWeekOf(res, Constants.ResolveToPast);
            }

            if (!string.IsNullOrEmpty(comment) && TimexUtility.HasDoubleTimex(comment))
            {
                TimexUtility.ProcessDoubleTimex(res, Constants.ResolveToFuture, Constants.ResolveToPast, timex);
            }

            foreach (var p in res)
            {
                if (p.Value is Dictionary <string, string> dictionary)
                {
                    var value = new Dictionary <string, string>();

                    AddResolutionFields(value, DateTimeResolutionKey.Timex, timex);
                    AddResolutionFields(value, DateTimeResolutionKey.Mod, mod);
                    AddResolutionFields(value, ResolutionKey.Type, typeOutput);
                    AddResolutionFields(value, DateTimeResolutionKey.IsLunar,
                                        isLunar ? isLunar.ToString(CultureInfo.InvariantCulture) : string.Empty);
                    AddResolutionFields(value, DateTimeResolutionKey.List, list);
                    AddResolutionFields(value, DateTimeResolutionKey.SourceEntity, sourceEntity);

                    if (hasTimeZone)
                    {
                        AddResolutionFields(value, Constants.TimeZone, val.TimeZoneResolution.Value);
                        AddResolutionFields(value, Constants.TimeZoneText, val.TimeZoneResolution.TimeZoneText);
                        AddResolutionFields(value, Constants.UtcOffsetMinsKey,
                                            val.TimeZoneResolution.UtcOffsetMins.ToString(CultureInfo.InvariantCulture));
                    }

                    foreach (var q in dictionary)
                    {
                        value[q.Key] = q.Value;
                    }

                    resolutions.Add(value);
                }
            }

            if (resolutionPast.Count == 0 && resolutionFuture.Count == 0 && val.TimeZoneResolution == null)
            {
                var notResolved = new Dictionary <string, string>
                {
                    {
                        DateTimeResolutionKey.Timex, timex
                    },
                    {
                        ResolutionKey.Type, typeOutput
                    },
                    {
                        ResolutionKey.Value, "not resolved"
                    },
                };

                resolutions.Add(notResolved);
            }

            return(new SortedDictionary <string, object> {
                { ResolutionKey.ValueSet, resolutions }
            });
        }
        public SortedDictionary <string, object> DateTimeResolution(DateTimeParseResult slot, bool hasRangeChangingMod)
        {
            var resolutions = new List <Dictionary <string, string> >();
            var res         = new Dictionary <string, object>();

            var val = (DateTimeResolutionResult)slot.Value;

            if (val is null)
            {
                return(null);
            }

            var type         = slot.Type;
            var typeOutput   = DetermineDateTimeType(slot.Type, hasRangeChangingMod);
            var sourceEntity = DetermineSourceEntityType(slot.Type, typeOutput, val.HasRangeChangingMod);
            var timex        = slot.TimexStr;

            var isLunar = val.IsLunar;
            var mod     = val.Mod;
            var comment = val.Comment;

            if (!string.IsNullOrEmpty(timex))
            {
                res.Add(DateTimeResolutionKey.Timex, timex);
            }

            if (!string.IsNullOrEmpty(comment))
            {
                res.Add(Constants.Comment, comment);
            }

            if (!string.IsNullOrEmpty(mod))
            {
                res.Add(DateTimeResolutionKey.Mod, mod);
            }

            if (!string.IsNullOrEmpty(type))
            {
                res.Add(ResolutionKey.Type, typeOutput);
            }

            var pastResolutionStr   = ((DateTimeResolutionResult)slot.Value).PastResolution;
            var futureResolutionStr = ((DateTimeResolutionResult)slot.Value).FutureResolution;

            var resolutionPast   = GenerateResolution(type, pastResolutionStr, mod);
            var resolutionFuture = GenerateResolution(type, futureResolutionStr, mod);

            // if past and future are same, keep only one
            if (resolutionFuture.OrderBy(t => t.Key).Select(t => t.Value).SequenceEqual(resolutionPast.OrderBy(t => t.Key).Select(t => t.Value)))
            {
                if (resolutionPast.Count > 0)
                {
                    res.Add(Constants.Resolve, resolutionPast);
                }
            }
            else
            {
                if (resolutionPast.Count > 0)
                {
                    res.Add(Constants.ResolveToPast, resolutionPast);
                }

                if (resolutionFuture.Count > 0)
                {
                    res.Add(Constants.ResolveToFuture, resolutionFuture);
                }
            }

            // if ampm, double our resolution accordingly
            if (comment is Constants.Comment_AmPm)
            {
                if (res.ContainsKey(Constants.Resolve))
                {
                    ResolveAmpm(res, Constants.Resolve);
                }
                else
                {
                    ResolveAmpm(res, Constants.ResolveToPast);
                    ResolveAmpm(res, Constants.ResolveToFuture);
                }
            }

            if (!string.IsNullOrEmpty(comment) && TimexUtility.HasDoubleTimex(comment))
            {
                ProcessDoubleTimex(res, Constants.ResolveToFuture, Constants.ResolveToPast, timex);
            }

            if (isLunar)
            {
                res.Add(DateTimeResolutionKey.IsLunar, isLunar);
            }

            foreach (var p in res)
            {
                if (p.Value is Dictionary <string, string> dictionary)
                {
                    var value = new Dictionary <string, string>();

                    if (!string.IsNullOrEmpty(timex))
                    {
                        value.Add(DateTimeResolutionKey.Timex, timex);
                    }

                    if (!string.IsNullOrEmpty(mod))
                    {
                        value.Add(DateTimeResolutionKey.Mod, mod);
                    }

                    if (!string.IsNullOrEmpty(type))
                    {
                        value.Add(ResolutionKey.Type, typeOutput);
                    }

                    if (!string.IsNullOrEmpty(sourceEntity))
                    {
                        value.Add(DateTimeResolutionKey.SourceEntity, sourceEntity);
                    }

                    foreach (var q in dictionary)
                    {
                        value[q.Key] = q.Value;
                    }

                    resolutions.Add(value);
                }
            }

            if (resolutionPast.Count == 0 && resolutionFuture.Count == 0)
            {
                var notResolved = new Dictionary <string, string>
                {
                    {
                        DateTimeResolutionKey.Timex, timex
                    },
                    {
                        ResolutionKey.Type, typeOutput
                    },
                    {
                        ResolutionKey.Value, "not resolved"
                    },
                };

                resolutions.Add(notResolved);
            }

            return(new SortedDictionary <string, object> {
                { ResolutionKey.ValueSet, resolutions }
            });
        }