In Python3, we have a function like this
Python 3.8.5 (v3.8.5:580fbb018f, Jul 20 2020, 12:11:27)
>>> from html import unescape
>>> unescaped = unescape("here is ' apostrophe")
>>> print(unescaped)
here is ' apostrophe
>>>
I'm having trouble finding an equivalent in Clojure. Does a base library function exist.
The library apache.commons.text can do this job:
(ns tst.demo.core
(:use tupelo.core tupelo.test)
(:import
[org.apache.commons.text StringEscapeUtils]))
(dotest
(let [hng "hi & goodbye"
encoded (StringEscapeUtils/escapeHtml4 hng)]
(is= encoded "hi & goodbye")
(is= hng (StringEscapeUtils/unescapeHtml4 encoded))))
The Apache site has the full API docs.
Related
I'm trying to convert a local-date into an instant with millis using java-time, but instant returns a timestamp without millis.
(def UTC (java-time/zone-id "UTC")
(defn local-date-to-instant [local-date]
(-> local-date
(.atStartOfDay UTC)
java-time/instant))
(local-date-to-instant (java-time/local-date))
=> #object[java.time.Instant 0xdb3a8c7 "2021-05-13T00:00:00Z"]
but
(java-time/instant)
=> #object[java.time.Instant 0x1d1c27c8 "2021-05-13T13:12:31.782Z"]
The service downstream expects a string in this format: yyyy-MM-ddTHH:mm:ss.SSSZ.
Create a DateTimeFormatter that prints an ISO instant with milliseconds (3 fractional digits) even if they are zeroes:
(ns steffan.overflow
(:require [java-time :as jt])
(:import (java.time.format DateTimeFormatterBuilder)))
(def iso-instant-ms-formatter
(-> (DateTimeFormatterBuilder.) (.appendInstant 3) .toFormatter))
Example of use:
(def today-inst (jt/truncate-to (jt/instant) :days))
(str today-inst) ; => "2021-05-13T00:00:00Z"
(jt/format iso-instant-ms-formatter today-inst) ; => "2021-05-13T00:00:00.000Z"
You need to use a DateTimeFormatter. Then you can write code like:
LocalDate date = LocalDate.now();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy MM dd");
String text = date.format(formatter);
In particular, look at these format pattern codes:
S fraction-of-second fraction 978
A milli-of-day number 1234
n nano-of-second number 987654321
I think the S code is the best one for your purposes. You'll have to experiment a bit as the docs don't have all the details.
Here is one example:
(ns tst.demo.core
(:use tupelo.core tupelo.test)
(:require
[schema.core :as s]
[tupelo.java-time :as tjt]
)
(:import
[java.time Instant LocalDate LocalDateTime ZonedDateTime]
[java.time.format DateTimeFormatter]
))
(dotest
(let [top-of-hour (tjt/trunc-to-hour (ZonedDateTime/now))
fmt (DateTimeFormatter/ofPattern "yyyy-MM-dd HH:mm:ss.SSS")
]
(spyx top-of-hour)
(spyx (.format top-of-hour fmt))
))
with result
-----------------------------------
Clojure 1.10.3 Java 15.0.2
-----------------------------------
Testing tst.demo.core
top-of-hour => #object[java.time.ZonedDateTime 0x9b64076 "2021-05-13T07:00-07:00[America/Los_Angeles]"]
(.format top-of-hour fmt) => "2021-05-13 07:00:00.000"
The above is based from this template project and the library tupelo.java-time.
LocalDate doesn't have a time component. .atStartOfDay puts zeroes in all time fields. A LocalDateTime can be converted to an Instant through .toInstant.
So, upfront, I'm super new at Clojure so this question may seem basic. I hava a txt file with 1 line that has a set number of intergers separated by a space. I need to read that data and populate a list so I can sort it later. I'm not asking how to do the sort, I need help populating the list with the string from the txt file.
My initial thought is to read the entire line of ints as one string, then split the string with a delimiter, and populate the list with the returned data, but I cant figure out how to do that in clojure. Any guidance is appreciated
Here is one way to do it, using some helper functions. Be sure to also bookmark:
The Clojure CheatSheet
Brave Clojure
Getting Clojure
(ns tst.demo.core
(:use demo.core tupelo.core tupelo.test)
(:require
[schema.core :as s]
[clojure.string :as str]))
(dotest
(let [filename "/tmp/dummy.txt"]
(spit filename "1 2 3 4 5")
(let-spy
[in-str (slurp filename)
nums-str (str/split in-str #"\W+")
nums (mapv #(Integer/parseInt %) nums-str)]
)))
with result:
-------------------------------
Clojure 1.10.0 Java 12
-------------------------------
Testing tst.demo.core
in-str => "1 2 3 4 5"
nums-str => ["1" "2" "3" "4" "5"]
nums => [1 2 3 4 5]
I'm trying to destructure an instant and get year, month, day.
I've tried with java-time/as function without success.
(ns myproject.time-test
(:require [java-time :as jt])
(:gen-class))
(def curr-time (jt/instant (System/currentTimeMillis)))
(jt/as curr-time :year)
Can anyone point me in the right direction?
I would do it without the .. to make it clear you are using Java interop (it appears that clojure.java-time has no wrapper to convert from an Instant to a ZonedDateTime:
(-> (jt/instant)
(.atZone (ZoneId/systemDefault)) ; => java ZonedDateTime obj
(.getYear))
=> 2018
There are other ways which may be useful:
(jt/zoned-date-time) => #object[java.time.ZonedDateTime 0x2585437a
"2018-07-19T11:42:37.093731-07:00[America/Los_Angeles]"]
(jt/year (jt/zoned-date-time)) => #object[java.time.Year 0x74694f06 "2018"]
(jt/year) => #object[java.time.Year 0x16c69c47 "2018"]
and also
(jt/as (jt/zoned-date-time) :year :month-of-year :day-of-month) => (2018 7 19)
Another way to convert an Instant to a ZonedDateTime:
(let [zdt (ZonedDateTime/ofInstant (jt/instant) (ZoneId/systemDefault))]
(.getYear zdt) => 2018
(.getMonth zdt) => #object[java.time.Month 0x403d9a5b "JULY"]
(.getDayOfMonth zdt) => 19
(ns mastering.stackoverflow
(:import
(java.time ZoneId)))
(.. (jt/instant)
(atZone (ZoneId/systemDefault))
(getYear))
Other methods like getMonthValue, getMinute are also available.
You could do "extraction" that way:
(let [i (.. (jt/instant)
(atZone (ZoneId/systemDefault)))
extract (juxt (memfn getYear) (memfn getMinute))]
(extract i))
; => [2018 37]
I just started to play with wit/duckling. It is written in Clojure and I have no previous experience in Clojure. I need to parse a string like 2016-08-14T19:45:48.000+05:30 to a format like 1945hrs, Sunday, August 14th 2016. I searched on Internet and came across to lib clj-time. After struggling with it for a long time I came across this thread and thought that rfc822 is my cup of tea. So I used formatter rfc822 but it is giving me exception:
java.lang.IllegalArgumentException: Invalid format: "2016-08-16T00:00:00.000+05:30"
Here is my code:
(ns firstproj.core
(:gen-class)
(:require [duckling.core :as p])
(:require [clj-time.format :as f]))
(defn -main
"I don't do a whole lot."
[x]
(p/load! { :languages ["en"]})
(def var_ (p/parse :en$core x [:time]))
(def date_string "2016-08-14T19:45:48.000+05:30")
(f/parse (f/formatters :rfc822) date_string))
So can anybody tell me what I am doing wrong here. Or any other way in Clojure to get my desired date-time format. As I am completely naive in Clojure, I request you to answer in detail, it will help me to understand this in a better way. Thank You.
The clj-time library is a wrapper for Joda-Time. If you're using Java 8, you should prefer the built-in java.time library over Joda-Time, for reasons explained here. In Clojure, you can use the Clojure.Java-Time library, which wraps java.time. First, add it to your dependencies:
[clojure.java-time "0.2.1"]
Then you can use the offset-date-time and format functions in the java-time namespace:
(require '[java-time :as time])
(->> (time/offset-date-time "2016-08-14T19:45:48.000+05:30")
(time/format "HHmm'hrs', EEEE, MMMM d y"))
;;=> "1945hrs, Sunday, August 14 2016"
As #Piotrek pointed out in his answer, Joda-Time doesn't seem to support the "th" in your original question. Judging from the DateTimeFormatter docs, neither does java.time.
Without actually checking which predefined formatter matches your date format you might just call:
(f/parse "2016-08-14T19:45:48.000+05:30")
;; => #object[org.joda.time.DateTime 0x1bd11b14 "2016-08-14T14:15:48.000Z"]
It will try all predefined formatters and return parsed value from the first one that succeeds.
Then to print in your custom format:
(require '[clj-time.core :as t])
(def my-time-zone (t/time-zone-for-offset 5 30))
(def my-formatter
(f/formatter
"HHmm'hrs', EEEE, MMMM dd yyyy"
my-time-zone))
(f/unparse my-formatter some-date)
;; => "1945hrs, Sunday, August 14 2016"
Unfortunately to my knowledge JodaTime doesn't handle things like adding st, nd, rd, th to days.
How do I call a function in one Clojure namespace, bene-csv.core from another namespace, bene-cmp.core? I've tried various flavors of :require and :use with no success.
Here is the function in bene-csv:
(defn ret-csv-data
"Returns a lazy sequence generated by parse-csv.
Uses open-csv-file which will return a nil, if
there is an exception in opening fnam.
parse-csv called on non-nil file, and that
data is returned."
[fnam]
(let [ csv-file (open-csv-file fnam)
csv-data (if-not (nil? csv-file)
(parse-csv csv-file)
nil)]
csv-data))
Here is the header of bene-cmp.core:
(ns bene-cmp.core
.
.
.
(:gen-class)
(:use [clojure.tools.cli])
(:require [clojure.string :as cstr])
(:use bene-csv.core)
(:use clojure-csv.core)
.
.
.
The calling function -- currently a stub -- in (bene-cmp.core)
defn fetch-csv-data
"This function merely loads the two csv file arguments."
[benetrak-csv-file gic-billing-file]
(let [benetrak-csv-data ret-csv-data]))
If I modify the header of bene-cmp.clj
(:require [bene-csv.core :as bcsv])
and change the call to ret-csv-data
(defn fetch-csv-data
"This function merely loads the two csv file arguments."
[benetrak-csv-file gic-billing-file]
(let [benetrak-csv-data bcsv/ret-csv-data]))
I get this error
Caused by: java.lang.RuntimeException: No such var: bcsv/ret-csv-data
So, how do I call fetch-csv-data?
Thank You.
You need to invoke the function, not just reference the var.
If you have this in your ns:
(:require [bene-csv.core :as bcsv])
Then you need to put parentheses around the namespace/alias qualified var to invoke it:
(let [benetrak-csv-data (bcsv/ret-csv-data arg)]
; stuff
)