source

UTC DateTime을 Web API HttpGet 메서드에 전달하면 로컬 시간이 됩니다.

myloves 2023. 3. 14. 22:11

UTC DateTime을 Web API HttpGet 메서드에 전달하면 로컬 시간이 됩니다.

웹 API 메서드에 UTC 날짜를 쿼리 문자열 매개 변수로 전달하려고 합니다.URL은 다음과 같습니다.

/api/order?endDate=2014-04-01T00:00:00Z&zoneId=4

메서드의 시그니처는 다음과 같습니다.

[HttpGet]
public object Index(int zoneId, DateTime? endDate = null)

31/03/2014 8:00:00 PM01/04/2014 12:00:00 AM

★★★JsonFormatter.SerializerSettings 모양입니다.

new JsonSerializerSettings
{
    ContractResolver = new CamelCasePropertyNamesContractResolver(),
    DateTimeZoneHandling = DateTimeZoneHandling.Utc,
    DateFormatHandling = DateFormatHandling.IsoDateFormat
};

: POST 때 된 ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★」2014-04-01T00:00:00ZC# UTC Date Time (UTC 날짜 시간)하지만, 저는 이 모든 것을 할 수 있는endDate.Value.ToUniversalTime()POST에서는 동작하지만 GET에서는 동작하지 않는 것이 이상하다고 생각합니다.

하는 값2014-04-01T00:00:00ZUTC ★★★★★★★★★★★★★★★」로컬 으로 한 되며, 콜을 됩니다.ToUniversalTime()UTC ★★★★★★★★★★★★★★★★★」

그럼, 정확히 어떤 질문이죠?쿼리 문자열로 전송되어도 요청 본문에 게시되어 있지 않은 경우 이 문제가 발생하는 이유에 대한 질문인 경우, 그 질문에 대한 답변은 이 ASP입니다.NET Web API는 모델 바인딩을 사용하여 URI 경로, 쿼리 문자열 등을 바인딩하고 본문은 파라미터 바인딩을 사용하여 바인딩합니다.후자의 경우 미디어 포맷터를 사용합니다.JSON을 전송하면 JSON 미디어 포맷터가 사용되며 JSON을 기반으로 합니다.그물.

「 」를 지정했기 에,DateTimeZoneHandling.Utc BTW로 하면 BTW가 됩니다.DateTimeZoneHandling.Local모델 바인딩과 동일한 동작을 볼 수 있습니다.

, 커스텀의 할 수 .TypeConverter:

public sealed class UtcDateTimeConverter : DateTimeConverter
{
    public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
    {
        return ((DateTime)base.ConvertFrom(context, culture, value)).ToUniversalTime();
    }
}

다음을 사용하여 배선합니다.

TypeDescriptor.AddAttributes(typeof(DateTime), new TypeConverterAttribute(typeof(UtcDateTimeConverter)));

파라미터가 'Da'로 되어 ' query string 파라미터는 'Da'로 인스턴스화 됩니다.DateTimeKind.Utc.

는 결국 ★★★★★★★★★★★★★★★★★★★★★★★★★★★ToUniversalTime()메서드를 지정합니다.

따라서 어플리케이션 전체에서 문자열에서 날짜로의 변환을 덮어쓰지 않고 날짜 파라미터를 사용하는 모든 메서드를 변경할 필요가 없는 사용자를 위해 웹 API 프로젝트에서 다음과 같이 하십시오.

최종적으로는, 여기서 일반적인 순서를 참조할 수 있습니다.

https://learn.microsoft.com/en-us/aspnet/web-api/overview/formats-and-model-binding/parameter-binding-in-aspnet-web-api#model-binders

이 케이스에 대한 전문 지침은 다음과 같습니다.

  1. "WebApiConfig" 클래스에서 다음을 추가합니다.

        var provider = new SimpleModelBinderProvider(typeof(DateTime),new UtcDateTimeModelBinder());
        config.Services.Insert(typeof(ModelBinderProvider), 0, provider);
    
  2. UtcDateTimeModelBinder라는 새 클래스를 만듭니다.

    public class UtcDateTimeModelBinder : IModelBinder
    {
        public bool BindModel(HttpActionContext actionContext,
            ModelBindingContext bindingContext)
        {
            if (bindingContext.ModelType != typeof(DateTime)) return false;
    
            var val = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
            if (val == null)
            {
                return false;
            }
    
            var key = val.RawValue as string;
            if (key == null)
            {
                bindingContext.ModelState.AddModelError(bindingContext.ModelName,
                    "Wrong value type");
                return false;
            }
    
            DateTime result;
            if (DateTime.TryParse(key, out result))
            {
                bindingContext.Model = result.ToUniversalTime();
                return true;
            }
    
            bindingContext.ModelState.AddModelError(bindingContext.ModelName,
                "Cannot convert value to Utc DateTime");
            return false;
        }
    }
    

드디어 이 코드를 찾았습니다.주요 답은 아니지만 경우에 따라서는 사용할 수 있습니다.

var dateUtc = TimeZoneInfo.ConvertTimeToUtc(date);

Date Time Offset(날짜 시간 오프셋)
버전화된 API 클래스는 내부 클래스에 자동으로 매핑됩니다.API의 URL 파라미터 모델에서 DateTimeOffset을 사용하여 DateTimeOffset = > DateTime 매핑을 추가하면 시간대 변환을 방지할 수 있습니다.예.

API 클래스:

public DateTimeOffset? SomeDateTime{ get; set; }

내부 클래스:

public DateTime? SomeDateTime{ get; set; }

매핑 프로파일:

CreateMap<DateTimeOffset, DateTime>();

[이 답변은 @SeanFausett의 답변으로 확대됩니다]

ISO 8601 날짜로 "Z"를 지정하고 Web api 함수가 이를 Utc Kind Date Time으로 수신할 수 있도록 하고 싶습니다.하지만 "Z"가 없으면 변환을 원하지 않습니다.

또한 들어오는 POST JSON 페이로드에서 날짜를 변환해야 했습니다.아래 함수는 문자열을 DateTime, DateTime?, DateTimeOffset 또는 DateTimeOffset으로 변환할 수 있습니다.

JSON 포스트 또는 URL 파라미터에 관계없이 날짜를 동일하게 해석하는 것이 편리합니다.원하는 대로 변환해 주세요.

//Register the two converters
var jSettings = new Newtonsoft.Json.JsonSerializerSettings()
jSettings.Converters.Add(new UtcDateTimeConverterJSON());
GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings = jSettings;

GlobalConfiguration.Configure(config =>
{
    TypeDescriptor.AddAttributes(typeof(DateTime), new TypeConverterAttribute(typeof(UtcDateTimeConverterURI)));
    WebApiConfig.Register(config);
}

//Date converter for URI parameters
public class UtcDateTimeConverterURI : DateTimeConverter
{
    public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
    {
        if (value?.GetType() == typeof(string))
        {
            return StringToDate(typeof(DateTime), (string)value, Path: "URI parameter");
        }
        else
        {
            return base.ConvertFrom(context, culture, value);
        }
    }

    /// <summary>
    /// Convert String to DateTime, DateTime?, DateTimeOffset, or DateTimeOffset?<br />
    /// Used for incoming JSON objects and URI parameters
    /// </summary>
    /// <param name="targetType">The type (i.e. typeof(DateTime))</param>
    /// <param name="sDate">string representation of date to be converted</param>
    /// <param name="Path">JSON Path in case of error, so the caller knows which parameter to fix</param>
    /// <returns></returns>
    /// <exception cref="Exception"></exception>
    public static object StringToDate(Type targetType, string sDate, string Path)
    {
        //if the object is a DateTime, determine if we need to return a UTC or Local date type
        bool returnUTC = false;

        //DateTime or DateTimeOffset return type
        bool isDateTimeOffset;
        if (targetType == typeof(DateTime?) || targetType == typeof(DateTime))
        {
            isDateTimeOffset = false;
        }
        else
        {
            isDateTimeOffset = true;
        }

        DateTimeOffset d;

        if (String.IsNullOrEmpty(sDate))
        {
            //if we have an empty string and the type is a nullable date, then return null... otherwise throw an error
            if (targetType == typeof(DateTime?))
            {
                return null;
            }
            else
            {
                throw new Exception(Path + " cannot be an empty Date");
            }
        }

        if (sDate[0] == '/')
        {
            // /Date(xxxxx)/ format
            sDate = sDate.Substring(6, sDate.Length - 8);
            var index = sDate.LastIndexOf('-');
            if (index == -1) index = sDate.LastIndexOf('+');
            if (index >= 0)
            {
                //lop off timezone offset
                sDate = sDate.Substring(0, index);
            }
            else
            {
                //no timezone offset, return as UTC
                returnUTC = true;
            }

            if (!Int64.TryParse(sDate, out var l))
            {
                //can't parse....
                throw new Exception(Path + " cannot be parsed as a Date");
            }
            else
            {
                d = DateTimeOffset.FromUnixTimeMilliseconds(l);
            }
        }
        else
        {
            //try and parse ISO8601 string
            if (!DateTimeOffset.TryParse(sDate, out d))
            {
                throw new Exception(Path + " cannot be parsed as a Date");
            }
            else
            {
                if (!isDateTimeOffset)
                {
                    //if UTC is specifically requested and we're not returning a DateTimeOffset, then make sure the return is UTC
                    if (d.Offset == TimeSpan.Zero && sDate[sDate.Length - 1] == 'Z') returnUTC = true;
                }
            }
        }

        if (isDateTimeOffset)
        {
            return d;
        }
        else
        {
            if (returnUTC)
            {
                return d.UtcDateTime;
            }
            else
            {
                //return the raw time passed in, forcing it to the "Local" Kind
                //for example:
                //"2020-03-27T12:00:00"       --> use 2020-03-27 12:00:00PM with Kind=Local
                //"2020-03-27T12:00:00-05:00" --> use 2020-03-27 12:00:00PM with Kind=Local
                return DateTime.SpecifyKind(d.DateTime, DateTimeKind.Local); //this will pull the raw time and force the Kind to "Local"
            }
        }
    }
}


//Date converter for JSON payloads
public class UtcDateTimeConverterJSON : DateTimeConverterBase
{
    public override bool CanRead
    {
        get
        {
            return true;
        }
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.Value == null || reader.TokenType == JsonToken.Date) return reader.Value;
        if (reader.TokenType != JsonToken.String) throw new Exception("Cannot parse Date");
    
        return UtcDateTimeConverterURI.StringToDate(objectType, (string)reader.Value, reader.Path);
    }
}

언급URL : https://stackoverflow.com/questions/22581138/passing-utc-datetime-to-web-api-httpget-method-results-in-local-time