haskell / time

A time library

Home Page:http://hackage.haskell.org/package/time

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Expose functions needed to create `ParseTime` instances

ygale opened this issue · comments

commented

I need to create ParseTime instances for some types in the timezone-series library. For that, it appears I need the timeParseTimeSpecifier function, and preferably also the timeSubstituteTimeSpecifier function. These exist in the time library, but they are hidden. Please expose them - even if only in an Internal module.

There does not appear to be any reasonable way to write good quality instances without these functions.

See ygale/timezone-olson#11 and ygale/timezone-series#11

EDIT: Updated to make the ask more explicit and clear.

commented

@AshleyYakeley ping

Is the recommended way to copy/paste the source code of these functions? That doesn't seem like a great idea.

Could you please expose these functions (even if only in an Internal module)? Thanks.

commented

Hmm I guess for now I could just re-use the implementation of parseTimeSpecifier and substituteTimeSpecifier from the TimeZone instance. Because for now the ParseTime instance of TimeZoneSeries can only build a trivial series with a single timezone.

Still a hack, but not nearly as bad as cut-and-paste of the those entire function bodies.

In principle, though, shouldn't these functions be exposed? Note that for your own instances you always use these directly; you do not copy them from other instances. If that is best practice, shouldn't new instances built by external libraries be allowed to do the same?

TBH I wasn't really expecting other people to create their own ParseTime or FormatTime instances?

What are the types you want instances for?

(and also which specifiers would work on them?)

commented

I create instances for TimeZoneSeries and ZoneSeriesTime.

For now at least, the specifiers are identical to the ones for TimeZone and ZonedTime, respectively. Because my instances are rather trivial - they can only create a TimeZoneSeries with a single TimeZone that is assumed to work for all eternity both backward and forward in time.

TBH I wasn't really expecting other people to create their own ParseTime or FormatTime instances?

@AshleyYakeley I upgraded the time library, and got bitten by this today. With an earlier version of the library I had written the following code to change the behaviour of %p and %P (to emit midnight and noon at 0000 hours and 1200 hours respectively):

newtype FormatTime12 t = FormatTime12 t

timeFormatterHelper :: (FormatTime t, Timeable t) => Char -> Maybe (TimeLocale -> Maybe NumericPadOption -> Maybe Int -> FormatTime12 t -> String)
timeFormatterHelper c = case (Time.formatCharacter c) of
    Nothing -> Nothing
    Just original ->
      let interceptChar tl npo mWidth tm@(FormatTime12 t) = case (t ^. hours, t ^. minutes) of
                                                     (0, 0) -> "midnight"
                                                     (24, 0) -> "midnight"
                                                     (12, 0) -> "noon"
                                                     _ -> runOriginal tl npo mWidth tm
          runOriginal tl npo mWidth (FormatTime12 t) = original tl npo mWidth t
      in if (c=='p' || c=='P')
         then Just interceptChar
         else Just runOriginal

instance FormatTime (FormatTime12 UTCTime) where
  formatCharacter = timeFormatterHelper

instance FormatTime (FormatTime12 LocalTime) where
  formatCharacter = timeFormatterHelper

instance FormatTime (FormatTime12 ZonedTime) where
  formatCharacter = timeFormatterHelper

instance FormatTime (FormatTime12 TimeOfDay) where
  formatCharacter = timeFormatterHelper

With the new version of the library, I cannot figure out how to do this because:

  • FormatOptions is not exposed to the outside world
  • formatting helpers, like formatString, formatNumber, formatNumberStd, etc are not exposed to the outside world.

What's the recommended way to do something like this in the time library?