Fork me on GitHub
#beginners
<
2016-06-24
>
danmidwood00:06:43

Here's another datetime question. Using clj-time, can I parse a string containing a timezone to create a datetime that has the same timezone applied? I have a string "2016-08-21T10:30:00.000-07:00" for example. Using the :date-time formatter this is converted to UTC (17:30). I know that I can timezone offset the formatter with something like (tf/parse (tf/with-zone (:date-time tf/formatters) (t/time-zone-for-offset -7)) "2016-08-21T10:30:00.000-07:00") but because not all of my times are in the same timezone I'd have parse them twice, first manually to get the timezone offset, then create the formatter and re-parse. That seems a bit backwards. So, is there a better way?

seancorfield01:06:37

(clj-time.local/to-local-date-time "2016-08-21T10:30:00.000-07:00")

seancorfield01:06:03

Is that what you’re looking for @danmidwood ?

seancorfield01:06:16

boot.user=> (clj-time.local/to-local-date-time "2016-08-21T10:30:00.000-07:00")
#object[org.joda.time.DateTime 0x2b383e7 "2016-08-21T10:30:00.000-07:00"]
boot.user=> (clj-time.core/to-time-zone *1 clj-time.core/utc)
#object[org.joda.time.DateTime 0x20dbe664 "2016-08-21T17:30:00.000Z"]

danmidwood01:06:59

Not quite, I want to parse it to whatever timezone is in the string, whereas that's parses to my local timezone instead

danmidwood01:06:26

user> (clj-time.local/to-local-date-time "2016-08-21T10:30:00.000-07:00")                                                                                                                                          
#object[org.joda.time.DateTime 0x21d15515 "2016-08-21T14:30:00.000-03:00"] 

danmidwood01:06:33

(I'm in UTC-3)

danmidwood01:06:53

This is what I'm looking for in result:

user> (clj-time.format/parse (clj-time.format/with-zone (:date-time clj-time.format/formatters) (t/time-zone-for-offset -7)) "2016-08-21T10:30:00.000-07:00")
#object[org.joda.time.DateTime 0x59d2709f "2016-08-21T10:30:00.000-07:00"]
user> (clj-time.format/parse (clj-time.format/with-zone (:date-time clj-time.format/formatters) (t/time-zone-for-offset -6)) "2016-08-21T10:30:00.000-06:00")
#object[org.joda.time.DateTime 0x3ad8cc29 "2016-08-21T10:30:00.000-06:00"]
user> (clj-time.format/parse (clj-time.format/with-zone (:date-time clj-time.format/formatters) (t/time-zone-for-offset -5)) "2016-08-21T10:30:00.000-05:00")
#object[org.joda.time.DateTime 0x67070511 "2016-08-21T10:30:00.000-05:00"]

danmidwood01:06:44

But to do it like this I have to already know the timezone, which I don't because I haven't parsed the string yet

seancorfield02:06:05

Ah, I just happened to pick a string that corresponded to my TZ. Oops.

seancorfield02:06:17

I guess I don’t really understand your use case...

seancorfield02:06:53

Where are you getting those time strings from in the first place? And why do you need to keep the (parsed) time in something other than UTC?

seancorfield02:06:18

(basically time values are absolute and don’t really have a TZ — the TZ only really exists in the external representation so under the hood it’s all UTC and you have to explicitly state the TZ you want for display)

danmidwood03:06:25

I agree, and I can't make excuses for it. We're working with an external API that has terrible date/time handling and I'm just trying to work with that.

bojan.matic09:06:21

@seancorfield: recently i had a really hard time convincing a team to handle time value exactly in the manner you described…they were very confused

Prakash09:06:09

Hi, I have a function that returns different functions based on conditions - somethin like -

(defn get-handler-fn [foo] 
(if (=“bar"  foo) fn-1 fn-2))

Prakash09:06:38

I am writing test cases for this functio, but how do I compare equality of functions

Prakash09:06:02

is identical? the function to check if two functions are same?

Prakash09:06:49

oh, nvm. = works fine for this as well.

agi_underground11:06:20

hello, someone know why when i am try to insert values into postgres like this: (sql/insert! db :users {:email (:email user) :password (:pass user) :username (:username user)}) in db u had field with free jspaces? most of columns 100 symbols length according db scheme. but when i try to compare same values from db and (noir.util.crypt/encrypt ourpass) its different, because i think problem if free spaces?

agi_underground11:06:17

db gives me pass like this "somehashingpass " - my pass to compare is "somehashingpass"

agi_underground11:06:15

i use [org.clojure/java.jdbc "0.6.1"]

agi_underground11:06:30

and driver [org.postgresql/postgresql "9.4.1208.jre7"]

zane14:06:20

Why oh why is this stuff not part of core?

seancorfield17:06:31

@zane: Because there’s no "one size fits all" with date/time stuff. Even Java has had three goes at it now (Date, Calendar, and the new Java Time stuff). At World Singles we use two different libraries: clj-time for heavy lifting UTC stuff, date-clj for the lighter stuff. We have all our servers and software configured for UTC and NTP sync’d. Date/time stuff is hard.

zane17:06:56

@seancorfield: I wasn't advocating for a one-size-fits-all solution. I was advocating for at least one official way to manipulate datetimes.

seancorfield17:06:47

I think most Clojurians consider clj-time to be the closest to "official" that we’re going to get.

seancorfield17:06:27

At least until Clojure requires Java 8 and we have have a clojure.time namespace that wraps Java Time — although I don’t know what the implication would be for ClojureScript at that point.

seancorfield17:06:00

There is a cljs version of clj-time — providing almost the exact same API (but, obviously, a completely different implementation).

seancorfield17:06:37

As one of the maintainers of clj-time, I can say that there’s immense pressure to support both UTC and local date/time equally — as well as a huge range of both functionality and coercions.

seancorfield17:06:16

A consideration for any "official" date/time support is that it not drag in external dependencies — which rules out clj-time — and that makes it less likely there will be any core namespace for date/time until Java 8 is the minimum supported version. (IMO)

zane18:06:07

Super-thoughtful response. Thanks, @seancorfield.

Alex Miller (Clojure team)18:06:06

@seancorfield: as of the next alpha, Clojure will extend the Inst protocol to java.time.Instant if you are using JDK 8+, which means that inst-ms and inst? will work on both that and java.util.Date

Alex Miller (Clojure team)18:06:59

it’s possible that more functions in the future might also build from that protocol, although I don’t have anything specific in mind or plan

Alex Miller (Clojure team)18:06:30

otherwise, I largely agree with the comments above - things are a mess because they are messy in the host

Alex Miller (Clojure team)18:06:20

the current approach is to effectively use Date as a typed wrapper for a long that is ms since the epoch - you get read/print support via the #inst tagged literal. The constructor functions used by #inst handle a variety of forms.

Alex Miller (Clojure team)18:06:13

I guess I left out that clojure.spec now has inst-in-range? predicate and inst-in spec (with gen support), which also build from Inst so work with either java.util.Date or (in next alpha) java.time.Instant or potentially anything you extend yourself to Inst, which could be the joda types

donaldball19:06:21

I am so hyped for the Inst protocol

Alex Miller (Clojure team)20:06:57

Do you lead a sheltered life? 😀

donaldball20:06:11

It’s the little things

zane21:06:44

❤️ omg omg omg ❤️

zane21:06:37

Really appreciate that additional context, alexmiller!

zane21:06:53

Is that documented anywhere else?

Alex Miller (Clojure team)22:06:24

I don’t think it’s doc’ed on the site anywhere right now (but would be great to add). There is a little in the changelog at https://github.com/clojure/clojure/blob/master/changes.md#211-instant-literals