2016-12-22 4 views
1

나는 ZonedTimeAesonServant 전환 수에 의해 befuzzled.ZonedTime fromJSON toJSON

Servant 앱으로 URL에 시간을 좀주세요 : .../2016-12-18T07:51:00+03:00/....

Servant... :> Capture "zt" ZonedTime :> ...으로 쉽게 ZonedTime으로 변환합니다.

내 응용 프로그램에서 몇 가지 계산을 수행하고 json-response에서 클라이언트에게이 시간과 일부 다른 ZonedTime을 돌려 주려고합니다. 클라이언트가이 시간을 다시 내 응용 프로그램에 제공하려는 경우를 대비해.

입력 시간대라면 영이 아닌 +0X:00 (X/= 0), 그 출력에 I는 +0X:00를 얻을 수 있지만, 입력에 I가 .../2016-12-18T07:51:00+00:00/... 주면 다음 반응 제가 2016-12-18T07:51:00Z을 얻는다. 이 문자열을 으로 다시 Servant에 공급하려고 시도하면 ServantZonedTime으로 변환되지 않습니다. 실제로는 HTTP 400 (Bad Request)입니다.

왜? 무엇 때문에?

답변

0

ISO 8601은 JSON에 사용 된 표준 텍스트 표현입니다. 표준 시간대가 UTC 인 경우 "+00 : 00"또는 "Z"가 유효한 시간대 접미사입니다. 그렇지 않으면 UTC라면 "Z"접미사를, 그렇지 않으면 "+ xx : xx"접미사를 사용하여 ISO 8601에서 Aeson 출력 시간을 보입니다. 아쉽게도 Servant (실제로는 Web.HttpApiData)는 "Z"접미사를 허용하지 않는 URL 조각에서 ZonedTime을 파싱하는 간단한 방법을 사용합니다. 대신 UTCTime을 구문 분석하면 "Z"접미어가 사용됩니다 (그리고 필요합니다). 그 실패 - -

이이 ZonedTime로 구문 분석하려고에 의해 두 형식을 모두 처리하는 다음과 같이 ZonedTime에 대한 newtype이란 별칭을 정의 할 수 있습니다 변환과 UTCTime :

module ZonedTimeTest where 

import Data.Time.LocalTime 
import Servant.API 

newtype ZonedTime' = ZonedTime' { getZonedTime :: ZonedTime } 

instance FromHttpApiData ZonedTime' where 
    parseUrlPiece u =  ZonedTime' <$> parseUrlPiece u   -- "...+xx:xx" 
        <!> ZonedTime' . fromUTC <$> parseUrlPiece u -- "...Z" 
    where fromUTC = utcToZonedTime utc 
      infixl 3 <!> 
      Left _ <!> y = y 
      x  <!> _ = x 

을 다음 Capture "zt" ZonedTime'은 모두 처리해야한다 형식을 사용해야합니다 (해당되는 경우 ZonedTime'ZonedTime으로 풀어야 함).

+0

아하. 명확한. 나는 먼저 'zonedtime'대신에 'utctime'을 사용하여 새로운 캡처 라인을 만들려고 노력할 것이고 Servant가 두 줄 사이에서 파견하는 것으로 관리한다면 보게 될 것입니다. – Dahan

0

확인.

그래서 빨리 ...Z 표기가 제대로 UTCTime으로 종에 의해 해석 될 때, 나는 또 다른 캡처 라인을 만든 :

:<|> "myendpoint" :> Capture "zt" ZonedTime :> ... 
:<|> "myendpoint" :> Capture "utct" UTCTime :> ... 

을 그리고 해당 핸들러를했다. 이 리터럴을 +xx:xx으로 가져오고 ZonedTime으로 가져오고 하나의 처리기로 이동하면 Z의 리터럴은 두 번째 줄로 가져와 첫 번째 처리기와 동일하게 처리하지만 UTC을 즉석에서 Zoned으로 변환합니다.


업데이트 나는 이해 나니 방법, 내 시스템이 URL에 내가 문자열 인코딩 시간의 다른 변이를 가진 될 수 있다는 사실에 리드를 작동하는 방법.

  1. 표준시 인 경우 시간대는 +03:00이거나 Z 일 수 있습니다.
  2. 나는 어느 Z 시간대 않으며, 분수 초와 같은 이해하지 못하는 ZonedTime에 대한 2016-12-09T15:04:26.349857693845+05:00

표준 Capture 같은 소수점 이하의 초를 가질 수있다.

다른 답변에서 제안 된대로 여기 어떻게 든했습니다.

나는 단 하나 개의 캡처 라인

"daymonth" :> Capture "zt" ZonedTime' :> Capture "fl" Double :> Get '[JSON] Value 

을 넣어 나는 새로운 형태의 ZonedTime', 즉 나를 위해 최선을 다하고되어 있는지 확인합니다.

newtype ZonedTime' = ZonedTime' { unwrap :: ZonedTime } 

instance FromHttpApiData ZonedTime' where 
    parseUrlPiece text = Right zt 
    where 
     strRaw = unpack text 
     str = subRegex (mkRegex "Z$") strRaw "+00:00" 
     zt = ZonedTime' (parseTimeOrError False defaultTimeLocale "%Y-%m-%dT%H:%M:%S%Q%z" str) 
  1. 나는
  2. +00:00 그런 다음 내가 수동으로 문자열의 구문 분석 초 %Q 어획량 소수 부분 형식 문자열을주는 쓰기로 대체, Z 문제를 해결.