public string ConvertToLocalizedTimeString(DateTime date, DateLocalizationOptions options = null) {
     return ConvertToLocalizedTimeString(ToNullable(date), options);
 }
        public DateTime? ConvertFromLocalizedString(string dateTimeString, DateLocalizationOptions options = null) {
            options = options ?? new DateLocalizationOptions();

            if (dateTimeString == null || dateTimeString == options.NullText) {
                return null;
            }

            var parts = _dateFormatter.ParseDateTime(dateTimeString);

            DateTime dateValue;
            if (options.EnableCalendarConversion && !(CurrentCalendar is GregorianCalendar)) {
                dateValue = ConvertFromSiteCalendar(parts);
            }
            else {
                dateValue = parts.ToDateTime(new GregorianCalendar());
            }

            if (options.EnableTimeZoneConversion) {
                dateValue = ConvertFromSiteTimeZone(dateValue);
            }

            return dateValue;
        }
 public string ConvertToLocalizedDateString(DateTime? date, DateLocalizationOptions options = null) {
     return ConvertToLocalizedString(date, _dateTimeFormatProvider.ShortDateFormat, options);
 }
        public DateTime? ConvertFromLocalizedString(string dateString, string timeString, DateLocalizationOptions options = null) {
            options = options ?? new DateLocalizationOptions();

            var hasDate = dateString != null && dateString != options.NullText;
            var hasTime = timeString != null && timeString != options.NullText;
            if (!hasDate && !hasTime) {
                return null;
            }

            var parts = new DateTimeParts(
                hasDate ? _dateFormatter.ParseDate(dateString) : DateParts.MinValue,
                hasTime ? _dateFormatter.ParseTime(timeString) : TimeParts.MinValue
            );

            DateTime dateValue;
            if (hasDate && options.EnableCalendarConversion && !(CurrentCalendar is GregorianCalendar)) {
                dateValue = ConvertFromSiteCalendar(parts);
            }
            else {
                dateValue = parts.ToDateTime(new GregorianCalendar());
            }

            if (hasTime && options.EnableTimeZoneConversion) {
                // If there is no date component (technically the date component is that of DateTime.MinValue) then
                // we must employ some trickery, for two reasons:
                // * DST can be active or not dependeng on the time of the year. We want the conversion to always act as if the time represents today, but we don't want that date stored.
                // * Time zone conversion cannot wrap DateTime.MinValue around to the previous day, resulting in undefined result.
                // Therefore we convert the date to today's date before the conversion, and back to DateTime.MinValue after.
                if (!hasDate) {
                    var now = _clock.UtcNow;
                    dateValue = new DateTime(now.Year, now.Month, now.Day, dateValue.Hour, dateValue.Minute, dateValue.Second, dateValue.Millisecond, dateValue.Kind);
                }
                dateValue = ConvertFromSiteTimeZone(dateValue);
                if (!hasDate) {
                    dateValue = new DateTime(DateTime.MinValue.Year, DateTime.MinValue.Month, DateTime.MinValue.Day, dateValue.Hour, dateValue.Minute, dateValue.Second, dateValue.Millisecond, dateValue.Kind);
                }
            }

            if (options.EnableTimeZoneConversion)
                dateValue = DateTime.SpecifyKind(dateValue, DateTimeKind.Utc);

            return dateValue;
        }
 public DateTime? ConvertFromLocalizedTimeString(string timeString, DateLocalizationOptions options = null) {
     return ConvertFromLocalizedString(null, timeString, options);
 }
 public DateTime? ConvertFromLocalizedDateString(string dateString, DateLocalizationOptions options = null) {
     return ConvertFromLocalizedString(dateString, null, options);
 }
        public string ConvertToLocalizedString(DateTime? date, string format, DateLocalizationOptions options = null) {
            options = options ?? new DateLocalizationOptions();

            if (!date.HasValue) {
                return options.NullText;
            }

            var dateValue = date.Value;
            var offset = TimeSpan.Zero;

            if (options.EnableTimeZoneConversion) {
                dateValue = ConvertToSiteTimeZone(dateValue);
                offset = CurrentTimeZone.GetUtcOffset(date.Value);
            }

            var parts = DateTimeParts.FromDateTime(dateValue, offset);
            if (options.EnableCalendarConversion && !(CurrentCalendar is GregorianCalendar)) {
                parts = ConvertToSiteCalendar(dateValue, offset);
            }

            return _dateFormatter.FormatDateTime(parts, format);
        }
        public string ConvertToLocalizedTimeString(DateTime? date, DateLocalizationOptions options = null) {
            options = options ?? new DateLocalizationOptions();

            if (!date.HasValue) {
                return options.NullText;
            }

            var dateValue = date.Value;
            var offset = TimeSpan.Zero;

            if (options.EnableTimeZoneConversion) {
                if (options.IgnoreDate) {
                    // The caller has asked us to ignore the date part and assume it is today. This usually because the source
                    // is a time-only field, in which case the date part is usually DateTime.MinValue which we should not use
                    // for the following reasons:
                    // * DST can be active or not dependeng on the time of the year. We want the conversion to always act as if the time represents today, but we don't want that date stored.
                    // * Time zone conversion cannot wrap DateTime.MinValue around to the previous day, resulting in undefined result.
                    // Therefore we convert the date to today's date before the conversion, and back to the original date after.
                    var today = _clock.UtcNow.Date;
                    var tempDate = new DateTime(today.Year, today.Month, today.Day, dateValue.Hour, dateValue.Minute, dateValue.Second, dateValue.Millisecond, dateValue.Kind);
                    tempDate = ConvertToSiteTimeZone(tempDate);
                    dateValue = new DateTime(dateValue.Year, dateValue.Month, dateValue.Day, tempDate.Hour, tempDate.Minute, tempDate.Second, tempDate.Millisecond, tempDate.Kind);
                }
                else {
                    dateValue = ConvertToSiteTimeZone(dateValue);
                }

                offset = CurrentTimeZone.GetUtcOffset(date.Value);
            }

            var parts = DateTimeParts.FromDateTime(dateValue, offset);
            
            // INFO: No calendar conversion in this method - we expect the date component to be DateTime.MinValue and irrelevant anyway.

            return _dateFormatter.FormatDateTime(parts, _dateTimeFormatProvider.LongTimeFormat);
        }