[AutoMapper] Convertir de Utc a determinada zona horaria

Dado un modelo como el siguiente:

public class User
{
	//Otras propiedades...
	public string TimeZoneId { get; set; }		
}

public class UserAction
{
	//Otras propiedades...
	public DateTime DateInUtc { get; set; }
}

Al registrar una acción del usuario registraremos la fecha en utc, pero a la hora de recuperarla y mostrarla al usuario, esta deberá ser de nuevo convertida, de Utc a la zona horaria del usuario. Si recuperamos una colección de acciones del usuario sería necesario crear una colección del ViewModel y en un bucle construir las fechas:

var timeZoneId = GetTimeZoneId();
var timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById(timeZoneId);
var userActions = GetUserActions();
var viewModel = new List<UserActionViewModel>();
foreach(var userAction in userActions)
{
	viewModel.Add(new UserActionViewModel()
		{
			ValidDate = TimeZoneInfo.ConvertTimeFromUtc(userAction.DateInUtc, timeZoneInfo)
		});
}

Podemos extraer el código y reutilizarlo para construir los ViewModels que necesitemos y hagan uso de las fechas y las zonas horarias. Pero si ya hemos incluido AutoMapper como una dependencia más de nuestro proyecto… ¿cómo lo podemos hacer?

IMappingOperationOptions y ValueResolver

AutoMapper ofrece la opción de “pasar información” al custom map haciendo uso de la segunda sobrecarga del método Map. Algo de la forma:

var timeZoneId = GetTimeZoneId();
var viewModel = Mapper.Map<UserActionViewModel>(userAction, opts=>opts.Items.Add("timezone", timeZoneId));

Y ahora ¿Cómo recuperamos dicho valor en el custom map?. Debemos convertir de alguna forma el valor de origen y recuperar el TimeZoneId. Para esto haremos uso de un ValueResolver, pues nos ofrece la posibilidad de acceder al contexto. Algo de la forma:

        class LocalizedDateTimeResolver : IValueResolver
        {
            public ResolutionResult Resolve(ResolutionResult source)
            {
                var timeZoneId = source.Context.Options.Items["timezone"].ToString();
                var utc = (DateTime)source.Value;
                var timezoneInfo = TimeZoneInfo.FindSystemTimeZoneById(timeZoneId);
                var dateTime = TimeZoneInfo.ConvertTimeFromUtc(utc, timezoneInfo);
                return source.New(dateTime);
            }
        }

Con esto, en el custom map podemos usar el método ResolveUsing, de la forma:

            Mapper.CreateMap<UserAction, UserActionViewModel>()
                .ForMember(des => des.ValidDate,
                    opts => opts.ResolveUsing<LocalizedDateTimeResolver>().FromMember(src => src.DateInUtc));

Espero les sea de utilidad. Hasta el próximo  post.

Anuncios
[AutoMapper] Convertir de Utc a determinada zona horaria

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s