Converting unix timestamp to human readable date and time in clojure - unix

The database query is returning the date and time in a unix timestamp. I am trying to use clojure to convert this into human readable time and then split the date and time into two separate columns under date and time.

Take a look at clj-time
For example here is how you would convert a (long) timestamp to DateTime:
user=> (clj-time.coerce/from-long 893362442345)
#<DateTime 1998-04-23T20:14:02.345Z>
Here is how to "split" it by date/time portions:
user=> (unparse (formatters :date) (clj-time.coerce/from-long 893362442345))
"1998-04-23"
user=> (unparse (formatters :time) (clj-time.coerce/from-long 893362442345))
"20:14:02.345Z"
Depending on how you need the result to be formatted, you can choose from many different built in formatters:
user=> (show-formatters)
:basic-date 20130828
:basic-date-time 20130828T175957.850Z
:basic-date-time-no-ms 20130828T175957Z
:basic-ordinal-date 2013240
:basic-ordinal-date-time 2013240T175957.850Z
:basic-ordinal-date-time-no-ms 2013240T175957Z
:basic-t-time T175957.850Z
:basic-t-time-no-ms T175957Z
:basic-time 175957.850Z
:basic-time-no-ms 175957Z
:basic-week-date 2013W353
:basic-week-date-time 2013W353T175957.850Z
:basic-week-date-time-no-ms 2013W353T175957Z
:date 2013-08-28
:date-hour 2013-08-28T17
:date-hour-minute 2013-08-28T17:59
:date-hour-minute-second 2013-08-28T17:59:57
:date-hour-minute-second-fraction 2013-08-28T17:59:57.850
:date-hour-minute-second-ms 2013-08-28T17:59:57.850
:date-time 2013-08-28T17:59:57.850Z
:date-time-no-ms 2013-08-28T17:59:57Z
:hour 17
:hour-minute 17:59
:hour-minute-second 17:59:57
:hour-minute-second-fraction 17:59:57.850
:hour-minute-second-ms 17:59:57.850
:mysql 2013-08-28 17:59:57
:ordinal-date 2013-240
:ordinal-date-time 2013-240T17:59:57.850Z
:ordinal-date-time-no-ms 2013-240T17:59:57Z
:rfc822 Wed, 28 Aug 2013 17:59:57 +0000
:t-time T17:59:57.850Z
:t-time-no-ms T17:59:57Z
:time 17:59:57.850Z
:time-no-ms 17:59:57Z
:week-date 2013-W35-3
:week-date-time 2013-W35-3T17:59:57.850Z
:week-date-time-no-ms 2013-W35-3T17:59:57Z
:weekyear 2013
:weekyear-week 2013-W35
:weekyear-week-day 2013-W35-3
:year 2013
:year-month 2013-08
:year-month-day 2013-08-28
or built a custom one:
(def custom-formatter (formatter "yyyyMMdd"))

Related

How to parse CCYY-MM-DDThh:mm:ss[.sss...] date format

As we all know, date parsing in Go has it's quirks*.
However, I have now come up against needing to parse a datetime string in CCYY-MM-DDThh:mm:ss[.sss...] to a valid date in Go.
This CCYY format is a format that seems to be ubiquitous in astronomy, essentially the CC is the current century, so although we're in 2022, the century is the 21st century, meaning the date in CCYY format would be 2122.
How do I parse a date string in this format, when we can't specify a coded layout?
Should I just parse in that format, and subtract one "century" e.g., 2106 becomes 2006 in the parsed datetime...?
Has anyone come up against this niche problem before?
*(I for one would never have been able to remember January 2nd, 3:04:05 PM of 2006, UTC-0700 if it wasn't the exact time of my birth! I got lucky)
The time package does not support parsing centuries. You have to handle it yourself.
Also note that a simple subtraction is not enough, as e.g. the 21st century takes place between January 1, 2001 and December 31, 2100 (the year may start with 20 or 21). If the year ends with 00, you do not have to subtract 100 years.
I would write a helper function to parse such dates:
func parse(s string) (t time.Time, err error) {
t, err = time.Parse("2006-01-02T15:04:05[.000]", s)
if err == nil && t.Year()%100 != 0 {
t = t.AddDate(-100, 0, 0)
}
return
}
Testing it:
fmt.Println(parse("2101-12-31T12:13:14[.123]"))
fmt.Println(parse("2122-10-29T12:13:14[.123]"))
fmt.Println(parse("2100-12-31T12:13:14[.123]"))
fmt.Println(parse("2201-12-31T12:13:14[.123]"))
Which outputs (try it on the Go Playground):
2001-12-31 12:13:14.123 +0000 UTC <nil>
2022-10-29 12:13:14.123 +0000 UTC <nil>
2100-12-31 12:13:14.123 +0000 UTC <nil>
2101-12-31 12:13:14.123 +0000 UTC <nil>
As for remembering the layout's time:
January 2, 15:04:05, 2006 (zone: -0700) is a common order in the US, and in this representation parts are in increasing numerical order: January is month 1, 15 hour is 3PM, year 2006 is 6. So the ordinals are 1, 2, 3, 4, 5, 6, 7.
I for one would never have been able to remember January 2nd, 3:04:05 PM of 2006, UTC-0700 if it wasn't the exact time of my birth! I got lucky.
The reason for the Go time package layout is that it is derived from the Unix (and Unix-like) date command format. For example, on Linux,
$ date
Fri Apr 15 08:20:43 AM EDT 2022
$
Now, count from left to right,
Month = 1
Day = 2
Hour = 3 (or 15 = 12 + 3)
Minute = 4
Second = 5
Year = 6
Note: Rob Pike is an author of The Unix Programming Environment

parse strange date format

I'm working on a Parser which Parses log files from a game so I can do analysis on auctions made within the game, however the date format that's being written by the logger seems to be causing problems as the format seems to be custom written for the logger, an example datetime stamp looks like: [Wed Nov 23 23:26:10 2016] I try to Parse it with:
func (r *AuctionReader) extractSaleInformation(line string) {
fmt.Println("Extracting information from: ", line)
// Format mask for output
layout := "DD-MM-YYYY hh:mm:ss"
// Replace the square brackets so we're just left with the date-time string
date := strings.TrimSpace(strings.Replace((strings.Split(line, "]")[0]), "[", "", -1))
fmt.Println(time.Parse(date, layout))
}
When I attempt to Parse the above date-time string I get the following error:
0001-01-01 00:00:00 +0000 UTC parsing time "DD-MM-YYYY hh:mm:ss" as "Wed Nov 23 23:26:10 2016": cannot parse "DD-MM-YYYY hh:mm:ss" as "Wed Nov "
How am I able to get the parser to recognise this seemingly custom format, I will be saving this data to Mongo so I don't want to store the auction time as a string as I want to query the timestamps individually.
Golang handle all date formatting in a unique way - it uses the reference time Mon Jan 2 15:04:05 MST 2006 (01/02 03:04:05PM '06 -0700) to show the pattern with which to format/parse a given time/string.
So, to read the format "Wed Nov 23 23:26:10 2016" you would put the reference date into that format: "Mon Jan 2 15:04:05 2006", and then do:
t, _ := time.Parse("Mon Jan 2 15:04:05 2006", "Wed Nov 23 23:26:10 2016")
Then, to output it in the given format, if you wanted the format DD-MM-YYYY hh:mm:ss, you would put the reference time into that format: 02-01-2006 15:04:05, and then do:
t.Format("02-01-2006 15:04:05")
https://play.golang.org/p/VO5413Z7-z
So basically, the main change is
// Format mask for output
layout := "DD-MM-YYYY hh:mm:ss"
should be
// Format mask for output
layout := "02-01-2006 15:04:05"
and
time.Parse(date, layout)
should be
time.Parse(layout, date)

In Clojure , how do you output a date like this 'Tue, 15-Jan-2013 21:47:38 GMT'?

This date format is used in HTTP Cookie Expires field.
This is my code so far
(ns cookie-handler
(:require[clj-time.format :as f])
(:import (org.joda.time DateTimeZone)))
(def custom-formatter2
(f/formatter "EEE, dd-MMM-yyyy HH:mm:ss zzz" (DateTimeZone/forID "Etc/GMT")))
I invoke this in repl
(f/unparse custom-formatter2 (c/to-date-time (.. (Calendar/getInstance) (getTime) )))
And this is what I get : "Thu, 23-Apr-2015 16:20:22 +00:00"
How do I initialize formatter so that it outputs a date string like "Thu, 23-Apr-2015 16:20:22 GMT"
There is a java version of this issue at java date format - GMT 0700 (PDT)
If all you want is to have GMT at the end of the formatted date string, you can add those characters to the end of the format string
(def custom1 (f/formatter-local "EEE, dd-MMM-yyyy HH:mm:ss 'GMT'"))
(def formatted-date-1 (f/unparse custom1 (t/now)))
"Thu, 23-Apr-2015 19:12:58 GMT"
If you really need GMT followed by the offset, the same idea applies
(def custom2 (f/formatter-local "EEE, dd-MMM-yyyy HH:mm:ss 'GMT'z"))
(def today (t/to-time-zone (t/now) (t/time-zone-for-offset -6)))
(def formatted-date-2 (f/unparse custom-formatter today))
"Thu, 23-Apr-2015 13:12:58 GMT-06:00"
I use the following in a library of mine that needs to output HTTP-spec compliant timestamps:
(def ^:private time-format (f/formatter "EEE, dd MMM yyyy HH:mm:ss"))
(defn- time->str
[time]
(str (f/unparse time-format time) " GMT"))
You can probably include GMT in the format string like G_A suggested, but I haven't tried that.
I do think that using f/formatter rather than f/formatter-local is important though, so that your local timestamp gets converted to UTC before it's converted to a string.

clj-time and displaying in user's time zone

I've been playing around with to-local-date-time, org.joda.time.DateTimeZone/getDefault, formatters, etc. and I still can't figure out how to get a datetime which I've stored as UTC to display in the user's time zone. Some formatters I can get to display the time, but it shows UTC time with an offset. If I have 2013-10-05T19:02:25.641-04:00, for example, how can I get it to display "2013-10-05 14:02:25"?
I think it's better to use build in timezone support from the formatter
(require '[clj-time.core :as t]
'[clj-time.format :as f])
(def custom-time-formatter (f/with-zone (f/formatter "yyyy-MM-dd hh:mm:ss")
(t/default-time-zone)))
(f/unparse custom-time-formatter (t/now))
instead of (t/default-time-zone) you can use a specific timezone or an offset (see clj-time.core documentation)
(maybe that didn't work in 2013 :) )
You can can apply the timezone with clj-time.core/to-time-zone, using clj-time.core/time-zone-for-offset when you only have the target offset, to get the localized time from your stored UTC.
There are numerous existing UTC formatters in the clj-time.format/formatters map, but you can always create your own from clj-time.format/formatter, or clj-time.format/formatter-local, and clj-time.format/unparse.
(require '[clj-time.core :as t]
'[clj-time.format :as f])
(defn formatlocal [n offset]
(let [nlocal (t/to-time-zone n (t/time-zone-for-offset offset))]
(f/unparse (f/formatter-local "yyyy-MM-dd hh:mm:ss aa")
nlocal)))
(formatlocal (t/now) -7)
2013-10-05T19:02:25.641-04:00 is the local time which would be UTC time 2013-10-05T23:02:25.641Z.
If you have a valid UTC time, do not try to convert it with to-local-date-time! to-local-date-time is a convenience function for changing the time zone on a DateTime instance without converting the time. To properly convert the time, use to-time-zone instead.
To format a DateTime without time zone information, use a custom formatter. Your example would be produced by the pattern "yyyy-MM-dd HH:mm:ss".
Example:
Define a UTC time:
time-test.core> (def t0 (date-time 2013 10 05 23 02 25 641))
#'time-test.core/t0
time-test.core> t0
#<DateTime 2013-10-05T23:02:25.641Z>
Convert it to a local time:
time-test.core> (def t1 (to-time-zone t0 (time-zone-for-offset -4)))
#'time-test.core/t1
time-test.core> t1
#<DateTime 2013-10-05T19:02:25.641-04:00>
Format the local time:
time-test.core> (unparse (formatter-local "yyyy-MM-dd HH:mm:ss") t1)
"2013-10-05 19:02:25"

How do I add dates in Emacs using Emacs Lisp?

I want to use Emacs Lisp to perform math operations like add and difference on dates and times.
The short answer is: read the System Interface section of the elisp info manual. More specifically, the time sections:
Time of day
Time conversion
Time parsing
Time calculations
The longer answer:
Emacs can work with time values as strings, floats, or a tuple of two or three integers. E.g. call some functions in the *scratch*buffer:
(current-time)
(19689 59702 984160)
(current-time-string)
"Sun Nov 21 20:54:22 2010"
(current-time-zone)
(-25200 "MST")
(float-time)
1290398079.965001
Let's some conversions:
(decode-time (current-time))
(33 7 21 21 11 2010 0 nil -25200)
(decode-time) ; (current-time) by default
(51 7 21 21 11 2010 0 nil -25200)
(let ((seconds 36)
(minutes 10)
(hour 21)
(day 21)
(month 11)
(year 2010))
(encode-time seconds minutes hour day month year))
(19689 60732)
(format-time-string "%A %e %B" (current-time))
"Sunday 21 November"
(seconds-to-time 23)
(0 23 0)
(time-to-seconds (current-time))
1290399309.598342
(time-to-days (current-time))
734097
Finally, to answer your question:
(time-add (current-time) (seconds-to-time 23))
(19689 60954 497526)
(time-subtract (current-time) (seconds-to-time 45))
(19689 61001 736330)

Resources