shih
shih

Reputation: 41

Converting Data.Time.UTCTime to / from ByteString

Let's say I need to do write/read of a Data.Time.UTCTime in "%Y-%m-%d %H:%M:%S" format many many times to/from a file.

It seems to me that, using Data.Time.formatTime or Data.Time.parseTime to convert UTCTime to/from String and then packing/unpacking the String to/from ByteString, would be too slow since it involves an intermediate String. But writing a ByteString builder/parser of UTCTime by hand seems like repeating a lot of work already done in formatTime and parseTime.

I guess my question is: Is there a systematic way to get functions of type t -> String or String -> t converted to t -> ByteString or ByteString -> t with increased efficiency without repeating a lot of work?

I am totally a Haskell newbie, so please forgive me if the question is just stupid.

Upvotes: 4

Views: 1289

Answers (2)

phipsgabler
phipsgabler

Reputation: 20980

If you're not really in the need of heavily optimized code, the usual and easiest way is to use function composition:

timeToByte = toBytes . formatTime
byteToTime = parseTime . fromBytes

or something like that, as I'm not familiar with those libraries.

If after profiling you recognize that this approach is still to slow, I guess you will have to write something by hand.

Upvotes: -3

Zopa
Zopa

Reputation: 668

No, there isn't a general way to convert a function of type t -> String to one of type t -> ByteString. It might help you reconcile yourself to that reality if you recall that a ByteString isn't just a faster String; it's lower-level than that. A ByteString is a sequence of bytes; it doesn't mean anything more unless you have an encoding in mind.

So your options are:

  1. Use function composition, as in phg's answer:

    import Data.ByteString.Char8 as B
    
    timeToByteStr :: UTCTime -> ByteString
    timeToByteStr = B.pack . formatTime'
    
    parseBStrTime :: ByteString -> Maybe UTCTime
    parseBStrTime = parseTime' . B.unpack
    

    where I've corrected the function names. I've also used, e.g., parseTime' instead of parseTime, to elide over the format string and TimeLocale you need to pass in.

    (It's also worth noting that Data.Text is often a better choice than Data.ByteString.Char8. The latter only works properly if your Chars fall in Unicode code points 0-255.)

  2. If performance is an issue and this conversion profiles out as a bottleneck, write a parser/builder.

  3. Just use Strings.

The last option is an underrated choice for Haskell newbies, IMHO. String is suboptimal, performance-wise, but it's not spawn-of-the-Devil. If you're just getting started with Haskell, why not keep your life as simple as possible, until and unless your code becomes too slow?

Upvotes: 5

Related Questions