[c#] 시간대를 우아하게 처리하는 방법



Answers

몇 가지 피드백을받은 후 깨끗하고 단순하며 일광 절약 문제를 다루는 최종 솔루션이라고 할 수 있습니다.

1 - 우리는 모델 수준에서 변환을 처리합니다. 따라서 Model 클래스에서 다음과 같이 작성합니다.

    public class Quote
    {
        ...
        public DateTime DateCreated
        {
            get { return CRM.Global.ToLocalTime(_DateCreated); }
            set { _DateCreated = value.ToUniversalTime(); }
        }
        private DateTime _DateCreated { get; set; }
        ...
    }

2 - 글로벌 도우미에서 사용자 정의 함수 "ToLocalTime"을 만듭니다.

    public static DateTime ToLocalTime(DateTime utcDate)
    {
        var localTimeZoneId = "China Standard Time";
        var localTimeZone = TimeZoneInfo.FindSystemTimeZoneById(localTimeZoneId);
        var localTime = TimeZoneInfo.ConvertTimeFromUtc(utcDate, localTimeZone);
        return localTime;
    }

3 - "China Standard Time"이라는 상수를 사용하는 대신 사용자 클래스에서 검색 할 수 있도록 각 사용자 프로필에 표준 시간대 ID를 저장하여이를 더 향상시킬 수 있습니다.

public class Contact
{
    ...
    public string TimeZone { get; set; }
    ...
}

4 - 여기서 사용자가 드롭 다운 상자에서 선택할 시간대 목록을 볼 수 있습니다.

public class ListHelper
{
    public IEnumerable<SelectListItem> GetTimeZoneList()
    {
        var list = from tz in TimeZoneInfo.GetSystemTimeZones()
                   select new SelectListItem { Value = tz.Id, Text = tz.DisplayName };

        return list;
    }
}

그래서, 현재 중국에서 오전 9시 25 분에, 미국에서 호스팅 된 웹 사이트는 데이터베이스에 UTC로 저장된 날짜입니다. 여기에 최종 결과가 있습니다.

5/9/2013 6:25:58 PM (Server - in USA) 
5/10/2013 1:25:58 AM (Database - Converted UTC)
5/10/2013 9:25:58 AM (Local - in China)

편집하다

원본 솔루션의 약한 부분을 지적 해 주신 John Johnson 에게 감사드립니다. 원래 게시물을 삭제하는 것에 대해 유감스럽게 생각하지만 올바른 코드 표시 형식을 얻는 데 문제가 있습니다 ... 편집기에서 "총알"과 "사전 코드"를 섞는 데 문제가 있으므로 글 머리 기호를 제거하고 괜찮 았어.

Question

응용 프로그램을 사용하는 사용자와 다른 시간대에 호스팅되는 웹 사이트가 있습니다. 이 외에도 사용자는 특정 시간대를 가질 수 있습니다. 다른 SO 사용자 및 응용 프로그램이 어떻게이 문제에 접근하고 있는지 궁금합니다. 가장 확실한 부분은 DB 내부에 날짜 / 시간이 UTC로 저장된다는 것입니다. 서버에서 모든 날짜 / 시간을 UTC로 처리해야합니다. 그러나 나는 극복하려는 세 가지 문제를 안다.

  1. 현재 시간을 UTC로 가져옴 ( DateTime.UtcNow 쉽게 해결됨).

  2. 데이터베이스에서 날짜 / 시간을 가져와 사용자에게 표시합니다. 다른보기에서 날짜를 인쇄하라는 호출이 잠재적으로 많이 있습니다. 나는이 문제를 해결할 수있는 뷰와 컨트롤러 사이에 어떤 레이어를 생각하고 있었다. 또는 DateTime 에 대한 사용자 지정 확장 메서드가 있습니다 (아래 참조). 주요 단점은 뷰에서 datetime을 사용하는 모든 위치에서 확장 메서드를 호출해야한다는 것입니다.

    또한 JsonResult 와 같은 것을 사용하는 데 어려움이 있습니다. 더 이상 Json(myEnumerable) 쉽게 호출 할 수 없으며 Json(myEnumerable.Select(transformAllDates)) 합니다. AutoMapper가이 상황에서 도움이 될 수 있습니까?

  3. 사용자로부터 입력 받기 (Local to UTC). 예를 들어 날짜가있는 양식을 게시하려면 날짜를 UTC로 변환해야합니다. 가장 먼저 떠오르는 것은 사용자 정의 ModelBinder 만드는 것입니다.

다음은보기에서 사용하는 확장 기능입니다.

public static class DateTimeExtensions
{
    public static DateTime UtcToLocal(this DateTime source, 
        TimeZoneInfo localTimeZone)
    {
        return TimeZoneInfo.ConvertTimeFromUtc(source, localTimeZone);
    }

    public static DateTime LocalToUtc(this DateTime source, 
        TimeZoneInfo localTimeZone)
    {
        source = DateTime.SpecifyKind(source, DateTimeKind.Unspecified);
        return TimeZoneInfo.ConvertTimeToUtc(source, localTimeZone);
    }
}

시간대를 다루는 것은 많은 응용 프로그램이 현재 서버의 현지 시간이 예상 시간대와 크게 다를 수있는 클라우드 기반이라는 점을 감안할 때 공통적 인 것이라고 생각합니다.

이전에 우아하게 해결 되었습니까? 제가 누락 된 것이 있습니까? 아이디어와 생각은 높이 평가됩니다.

편집 : 좀 더 자세한 내용을 추가 할 생각 일부 혼란을 정리하십시오. 문제는 현재 데이터베이스에 UTC 시간을 저장 하는 방법 이 아니라 UTC -> 로컬 및 로컬 -> UTC에서 진행하는 프로세스에 관한 것입니다. @Max Zerbini가 지적했듯이 UTC-> Local 코드를보기에 넣는 것이 현명하지만 DateTimeExtensions 실제로 사용하고 있습니까? 사용자로부터 입력을받을 때, 사용자의 현지 시간으로 날짜를 받아 들여서 (JS가 사용하기 때문에) 날짜를 수락 한 다음 ModelBinder 를 사용하여 UTC로 변환하는 것이 ModelBinder 입니까? 사용자의 시간대는 DB에 저장되어 쉽게 검색 할 수 있습니다.




이것은 제 견해입니다, 나는 MVC 응용 프로그램이 데이터 모델 관리로부터 데이터 표현 문제를 분리해야한다고 생각합니다. 데이터베이스는 로컬 서버 시간에 데이터를 저장할 수 있지만 로컬 사용자 시간대를 사용하여 datetime을 렌더링하는 것은 프리젠 테이션 계층의 의무입니다. 이것은 나에게 다른 나라의 I18N 및 숫자 형식과 같은 문제인 것처럼 보입니다. 귀하의 응용 프로그램은 사용자의 Culture 와 시간대를 감지하고 다른 텍스트, 숫자 및 날짜 표현을 보여주는보기를 변경해야하지만 저장된 데이터는 동일한 형식을 가질 수 있습니다.




이것은 아마 너트를 해독하는 데 큰 어려움이 있지만 반환 된 객체 그래프에서 현지 시간으로 투명하게 datetime을 변환하는 UI와 비즈니스 레이어 사이에 레이어를 삽입 할 수 있으며 입력 된 datetime 매개 변수에 대해서는 UTC로 삽입 할 수 있습니다.

PostSharp 또는 컨트롤 컨테이너의 일부 반전을 사용하여이 작업을 수행 할 수 있다고 상상해보십시오.

개인적으로, 나는 명시 적으로 UI의 datetimes를 변환하는 것으로 갈 것입니다 ...




Links